Index: projects/release-pkg/share/misc/committers-src.dot =================================================================== --- projects/release-pkg/share/misc/committers-src.dot (revision 294447) +++ projects/release-pkg/share/misc/committers-src.dot (revision 294448) @@ -1,757 +1,759 @@ # $FreeBSD$ # This file is meant to list all FreeBSD src committers and describe the # mentor-mentee relationships between them. # The graphical output can be generated from this file with the following # command: # $ dot -T png -o file.png committers-src.dot # # The dot binary is part of the graphics/graphviz port. digraph src { # Node definitions follow this example: # # foo [label="Foo Bar\nfoo@FreeBSD.org\n????/??/??"] # # ????/??/?? is the date when the commit bit was obtained, usually the one you # can find looking at svn logs for the svnadmin/access file. # Use YYYY/MM/DD format. # # For returned commit bits, the node definition will follow this example: # # foo [label="Foo Bar\nfoo@FreeBSD.org\n????/??/??\n????/??/??"] # # The first date is the same as for an active committer, the second date is # the date when the commit bit has been returned. Again, check svn logs. node [color=grey62, style=filled, bgcolor=black]; # Alumni go here.. Try to keep things sorted. alm [label="Andrew Moore\nalm@FreeBSD.org\n1993/06/12\n????/??/??"] anholt [label="Eric Anholt\nanholt@FreeBSD.org\n2002/04/22\n2008/08/07"] archie [label="Archie Cobbs\narchie@FreeBSD.org\n1998/11/06\n2006/06/09"] arr [label="Andrew R. Reiter\narr@FreeBSD.org\n2001/11/02\n2005/05/25"] arun [label="Arun Sharma\narun@FreeBSD.org\n2003/03/06\n2006/12/16"] asmodai [label="Jeroen Ruigrok\nasmodai@FreeBSD.org\n1999/12/16\n2001/11/16"] benjsc [label="Benjamin Close\nbenjsc@FreeBSD.org\n2007/02/09\n2010/09/15"] billf [label="Bill Fumerola\nbillf@FreeBSD.org\n1998/11/11\n2008/11/10"] bmah [label="Bruce A. Mah\nbmah@FreeBSD.org\n2002/01/29\n2009/09/13"] bmilekic [label="Bosko Milekic\nbmilekic@FreeBSD.org\n2000/09/21\n2008/11/10"] bushman [label="Michael Bushkov\nbushman@FreeBSD.org\n2007/03/10\n2010/04/29"] carl [label="Carl Delsey\ncarl@FreeBSD.org\n2013/01/14\n2014/03/06"] ceri [label="Ceri Davies\nceri@FreeBSD.org\n2006/11/07\n2012/03/07"] cjc [label="Crist J. Clark\ncjc@FreeBSD.org\n2001/06/01\n2006/12/29"] davidxu [label="David Xu\ndavidxu@FreeBSD.org\n2002/09/02\n2014/04/14"] dds [label="Diomidis Spinellis\ndds@FreeBSD.org\n2003/06/20\n2010/09/22"] dhartmei [label="Daniel Hartmeier\ndhartmei@FreeBSD.org\n2004/04/06\n2008/12/08"] dmlb [label="Duncan Barclay\ndmlb@FreeBSD.org\n2001/12/14\n2008/11/10"] dougb [label="Doug Barton\ndougb@FreeBSD.org\n2000/10/26\n2012/10/08"] eik [label="Oliver Eikemeier\neik@FreeBSD.org\n2004/05/20\n2008/11/10"] furuta [label="Atsushi Furuta\nfuruta@FreeBSD.org\n2000/06/21\n2003/03/08"] gj [label="Gary L. Jennejohn\ngj@FreeBSD.org\n1994/??/??\n2006/04/28"] groudier [label="Gerard Roudier\ngroudier@FreeBSD.org\n1999/12/30\n2006/04/06"] jake [label="Jake Burkholder\njake@FreeBSD.org\n2000/05/16\n2008/11/10"] jayanth [label="Jayanth Vijayaraghavan\njayanth@FreeBSD.org\n2000/05/08\n2008/11/10"] jb [label="John Birrell\njb@FreeBSD.org\n1997/03/27\n2009/12/15"] jdp [label="John Polstra\njdp@FreeBSD.org\n1995/12/07\n2008/02/26"] jedgar [label="Chris D. Faulhaber\njedgar@FreeBSD.org\n1999/12/15\n2006/04/07"] jkh [label="Jordan K. Hubbard\njkh@FreeBSD.org\n1993/06/12\n2008/06/13"] jlemon [label="Jonathan Lemon\njlemon@FreeBSD.org\n1997/08/14\n2008/11/10"] joe [label="Josef Karthauser\njoe@FreeBSD.org\n1999/10/22\n2008/08/10"] jtc [label="J.T. Conklin\njtc@FreeBSD.org\n1993/06/12\n????/??/??"] kargl [label="Steven G. Kargl\nkargl@FreeBSD.org\n2011/01/17\n2015/06/28"] kbyanc [label="Kelly Yancey\nkbyanc@FreeBSD.org\n2000/07/11\n2006/07/25"] keichii [label="Michael Wu\nkeichii@FreeBSD.org\n2001/03/07\n2006/04/28"] linimon [label="Mark Linimon\nlinimon@FreeBSD.org\n2006/09/30\n2008/05/04"] lulf [label="Ulf Lilleengen\nlulf@FreeBSD.org\n2007/10/24\n2012/01/19"] mb [label="Maxim Bolotin\nmb@FreeBSD.org\n2000/04/06\n2003/03/08"] marks [label="Mark Santcroos\nmarks@FreeBSD.org\n2004/03/18\n2008/09/29"] mike [label="Mike Barcroft\nmike@FreeBSD.org\n2001/07/17\n2006/04/28"] msmith [label="Mike Smith\nmsmith@FreeBSD.org\n1996/10/22\n2003/12/15"] murray [label="Murray Stokely\nmurray@FreeBSD.org\n2000/04/05\n2010/07/25"] mux [label="Maxime Henrion\nmux@FreeBSD.org\n2002/03/03\n2011/06/22"] nate [label="Nate Willams\nnate@FreeBSD.org\n1993/06/12\n2003/12/15"] njl [label="Nate Lawson\nnjl@FreeBSD.org\n2002/08/07\n2008/02/16"] non [label="Noriaki Mitsnaga\nnon@FreeBSD.org\n2000/06/19\n2007/03/06"] onoe [label="Atsushi Onoe\nonoe@FreeBSD.org\n2000/07/21\n2008/11/10"] rafan [label="Rong-En Fan\nrafan@FreeBSD.org\n2007/01/31\n2012/07/23"] randi [label="Randi Harper\nrandi@FreeBSD.org\n2010/04/20\n2012/05/10"] rgrimes [label="Rod Grimes\nrgrimes@FreeBSD.org\n1993/06/12\n2003/03/08"] rink [label="Rink Springer\nrink@FreeBSD.org\n2006/01/16\n2010/11/04"] robert [label="Robert Drehmel\nrobert@FreeBSD.org\n2001/08/23\n2006/05/13"] sah [label="Sam Hopkins\nsah@FreeBSD.org\n2004/12/15\n2008/11/10"] shafeeq [label="Shafeeq Sinnamohideen\nshafeeq@FreeBSD.org\n2000/06/19\n2006/04/06"] sheldonh [label="Sheldon Hearn\nsheldonh@FreeBSD.org\n1999/06/14\n2006/05/13"] shiba [label="Takeshi Shibagaki\nshiba@FreeBSD.org\n2000/06/19\n2008/11/10"] shin [label="Yoshinobu Inoue\nshin@FreeBSD.org\n1999/07/29\n2003/03/08"] snb [label="Nick Barkas\nsnb@FreeBSD.org\n2009/05/05\n2010/11/04"] tmm [label="Thomas Moestl\ntmm@FreeBSD.org\n2001/03/07\n2006/07/12"] toshi [label="Toshihiko Arai\ntoshi@FreeBSD.org\n2000/07/06\n2003/03/08"] tshiozak [label="Takuya SHIOZAKI\ntshiozak@FreeBSD.org\n2001/04/25\n2003/03/08"] uch [label="UCHIYAMA Yasushi\nuch@FreeBSD.org\n2000/06/21\n2002/04/24"] wilko [label="Wilko Bulte\nwilko@FreeBSD.org\n2000/01/13\n2013/01/17"] yar [label="Yar Tikhiy\nyar@FreeBSD.org\n2001/03/25\n2012/05/23"] zack [label="Zack Kirsch\nzack@FreeBSD.org\n2010/11/05\n2012/09/08"] node [color=lightblue2, style=filled, bgcolor=black]; # Current src committers go here. Try to keep things sorted. ache [label="Andrey Chernov\nache@FreeBSD.org\n1993/10/31"] achim [label="Achim Leubner\nachim@FreeBSD.org\n2013/01/23"] adrian [label="Adrian Chadd\nadrian@FreeBSD.org\n2000/07/03"] ae [label="Andrey V. Elsukov\nae@FreeBSD.org\n2010/06/03"] akiyama [label="Shunsuke Akiyama\nakiyama@FreeBSD.org\n2000/06/19"] alc [label="Alan Cox\nalc@FreeBSD.org\n1999/02/23"] allanjude [label="Allan Jude\nallanjude@FreeBSD.org\n2015/07/30"] ambrisko [label="Doug Ambrisko\nambrisko@FreeBSD.org\n2001/12/19"] anchie [label="Ana Kukec\nanchie@FreeBSD.org\n2010/04/14"] andre [label="Andre Oppermann\nandre@FreeBSD.org\n2003/11/12"] andreast [label="Andreas Tobler\nandreast@FreeBSD.org\n2010/09/05"] andrew [label="Andrew Turner\nandrew@FreeBSD.org\n2010/07/19"] antoine [label="Antoine Brodin\nantoine@FreeBSD.org\n2008/02/03"] araujo [label="Marcelo Araujo\naraujo@FreeBSD.org\n2015/08/04"] ariff [label="Ariff Abdullah\nariff@FreeBSD.org\n2005/11/14"] art [label="Artem Belevich\nart@FreeBSD.org\n2011/03/29"] arybchik [label="Andrew Rybchenko\narybchik@FreeBSD.org\n2014/10/12"] asomers [label="Alan Somers\nasomers@FreeBSD.org\n2013/04/24"] avg [label="Andriy Gapon\navg@FreeBSD.org\n2009/02/18"] avos [label="Andriy Voskoboinyk\navos@FreeBSD.org\n2015/09/24"] bapt [label="Baptiste Daroussin\nbapt@FreeBSD.org\n2011/12/23"] bdrewery [label="Bryan Drewery\nbdrewery@FreeBSD.org\n2013/12/14"] benl [label="Ben Laurie\nbenl@FreeBSD.org\n2011/05/18"] benno [label="Benno Rice\nbenno@FreeBSD.org\n2000/11/02"] bms [label="Bruce M Simpson\nbms@FreeBSD.org\n2003/08/06"] br [label="Ruslan Bukin\nbr@FreeBSD.org\n2013/09/02"] brian [label="Brian Somers\nbrian@FreeBSD.org\n1996/12/16"] brooks [label="Brooks Davis\nbrooks@FreeBSD.org\n2001/06/21"] brucec [label="Bruce Cran\nbrucec@FreeBSD.org\n2010/01/29"] brueffer [label="Christian Brueffer\nbrueffer@FreeBSD.org\n2006/02/28"] bruno [label="Bruno Ducrot\nbruno@FreeBSD.org\n2005/07/18"] bryanv [label="Bryan Venteicher\nbryanv@FreeBSD.org\n2012/11/03"] bschmidt [label="Bernhard Schmidt\nbschmidt@FreeBSD.org\n2010/02/06"] bz [label="Bjoern A. Zeeb\nbz@FreeBSD.org\n2004/07/27"] cem [label="Conrad Meyer\ncem@FreeBSD.org\n2015/07/05"] cognet [label="Olivier Houchard\ncognet@FreeBSD.org\n2002/10/09"] cokane [label="Coleman Kane\ncokane@FreeBSD.org\n2000/06/19"] cperciva [label="Colin Percival\ncperciva@FreeBSD.org\n2004/01/20"] csjp [label="Christian S.J. Peron\ncsjp@FreeBSD.org\n2004/05/04"] das [label="David Schultz\ndas@FreeBSD.org\n2003/02/21"] davide [label="Davide Italiano\ndavide@FreeBSD.org\n2012/01/27"] dchagin [label="Dmitry Chagin\ndchagin@FreeBSD.org\n2009/02/28"] delphij [label="Xin Li\ndelphij@FreeBSD.org\n2004/09/14"] des [label="Dag-Erling Smorgrav\ndes@FreeBSD.org\n1998/04/03"] dfr [label="Doug Rabson\ndfr@FreeBSD.org\n????/??/??"] dg [label="David Greenman\ndg@FreeBSD.org\n1993/06/14"] dim [label="Dimitry Andric\ndim@FreeBSD.org\n2010/08/30"] dteske [label="Devin Teske\ndteske@FreeBSD.org\n2012/04/10"] dumbbell [label="Jean-Sebastien Pedron\ndumbbell@FreeBSD.org\n2004/11/29"] dwmalone [label="David Malone\ndwmalone@FreeBSD.org\n2000/07/11"] eadler [label="Eitan Adler\neadler@FreeBSD.org\n2012/01/18"] ed [label="Ed Schouten\ned@FreeBSD.org\n2008/05/22"] edavis [label="Eric Davis\nedavis@FreeBSD.org\n2013/10/09"] edwin [label="Edwin Groothuis\nedwin@FreeBSD.org\n2007/06/25"] eivind [label="Eivind Eklund\neivind@FreeBSD.org\n1997/02/02"] emaste [label="Ed Maste\nemaste@FreeBSD.org\n2005/10/04"] emax [label="Maksim Yevmenkin\nemax@FreeBSD.org\n2003/10/12"] eri [label="Ermal Luci\neri@FreeBSD.org\n2008/06/11"] erj [label="Eric Joyner\nerj@FreeBSD.org\n2014/12/14"] fabient [label="Fabien Thomas\nfabient@FreeBSD.org\n2009/03/16"] fanf [label="Tony Finch\nfanf@FreeBSD.org\n2002/05/05"] fjoe [label="Max Khon\nfjoe@FreeBSD.org\n2001/08/06"] flz [label="Florent Thoumie\nflz@FreeBSD.org\n2006/03/30"] gabor [label="Gabor Kovesdan\ngabor@FreeBSD.org\n2010/02/02"] gad [label="Garance A. Drosehn\ngad@FreeBSD.org\n2000/10/27"] gallatin [label="Andrew Gallatin\ngallatin@FreeBSD.org\n1999/01/15"] gavin [label="Gavin Atkinson\ngavin@FreeBSD.org\n2009/12/07"] gibbs [label="Justin T. Gibbs\ngibbs@FreeBSD.org\n????/??/??"] gjb [label="Glen Barber\ngjb@FreeBSD.org\n2013/06/04"] gleb [label="Gleb Kurtsou\ngleb@FreeBSD.org\n2011/09/19"] glebius [label="Gleb Smirnoff\nglebius@FreeBSD.org\n2004/07/14"] gnn [label="George V. Neville-Neil\ngnn@FreeBSD.org\n2004/10/11"] gordon [label="Gordon Tetlow\ngordon@FreeBSD.org\n2002/05/17"] grehan [label="Peter Grehan\ngrehan@FreeBSD.org\n2002/08/08"] grog [label="Greg Lehey\ngrog@FreeBSD.org\n1998/08/30"] gshapiro [label="Gregory Shapiro\ngshapiro@FreeBSD.org\n2000/07/12"] harti [label="Hartmut Brandt\nharti@FreeBSD.org\n2003/01/29"] hiren [label="Hiren Panchasara\nhiren@FreeBSD.org\n2013/04/12"] hmp [label="Hiten Pandya\nhmp@FreeBSD.org\n2004/03/23"] ian [label="Ian Lepore\nian@FreeBSD.org\n2013/01/07"] iedowse [label="Ian Dowse\niedowse@FreeBSD.org\n2000/12/01"] imp [label="Warner Losh\nimp@FreeBSD.org\n1996/09/20"] ivoras [label="Ivan Voras\nivoras@FreeBSD.org\n2008/06/10"] jah [label="Jason A. Harmening\njah@FreeBSD.org\n2015/03/08"] jamie [label="Jamie Gritton\njamie@FreeBSD.org\n2009/01/28"] jasone [label="Jason Evans\njasone@FreeBSD.org\n1999/03/03"] jceel [label="Jakub Klama\njceel@FreeBSD.org\n2011/09/25"] jch [label="Julien Charbon\njch@FreeBSD.org\n2014/09/24"] jchandra [label="Jayachandran C.\njchandra@FreeBSD.org\n2010/05/19"] jeff [label="Jeff Roberson\njeff@FreeBSD.org\n2002/02/21"] jh [label="Jaakko Heinonen\njh@FreeBSD.org\n2009/10/02"] jhb [label="John Baldwin\njhb@FreeBSD.org\n1999/08/23"] jhibbits [label="Justin Hibbits\njhibbits@FreeBSD.org\n2011/11/30"] jilles [label="Jilles Tjoelker\njilles@FreeBSD.org\n2009/05/22"] jimharris [label="Jim Harris\njimharris@FreeBSD.org\n2011/12/09"] jinmei [label="JINMEI Tatuya\njinmei@FreeBSD.org\n2007/03/17"] jkim [label="Jung-uk Kim\njkim@FreeBSD.org\n2005/07/06"] jkoshy [label="A. Joseph Koshy\njkoshy@FreeBSD.org\n1998/05/13"] jlh [label="Jeremie Le Hen\njlh@FreeBSD.org\n2012/04/22"] jls [label="Jordan Sissel\njls@FreeBSD.org\n2006/12/06"] jmg [label="John-Mark Gurney\njmg@FreeBSD.org\n1997/02/13"] jmmv [label="Julio Merino\njmmv@FreeBSD.org\n2013/11/02"] joerg [label="Joerg Wunsch\njoerg@FreeBSD.org\n1993/11/14"] jon [label="Jonathan Chen\njon@FreeBSD.org\n2000/10/17"] jonathan [label="Jonathan Anderson\njonathan@FreeBSD.org\n2010/10/07"] jpaetzel [label="Josh Paetzel\njpaetzel@FreeBSD.org\n2011/01/21"] jtl [label="Jonathan T. Looney\njtl@FreeBSD.org\n2015/10/26"] julian [label="Julian Elischer\njulian@FreeBSD.org\n1993/04/19"] jwd [label="John De Boskey\njwd@FreeBSD.org\n2000/05/19"] kaiw [label="Kai Wang\nkaiw@FreeBSD.org\n2007/09/26"] kan [label="Alexander Kabaev\nkan@FreeBSD.org\n2002/07/21"] ken [label="Ken Merry\nken@FreeBSD.org\n1998/09/08"] kensmith [label="Ken Smith\nkensmith@FreeBSD.org\n2004/01/23"] kevlo [label="Kevin Lo\nkevlo@FreeBSD.org\n2006/07/23"] kib [label="Konstantin Belousov\nkib@FreeBSD.org\n2006/06/03"] kmacy [label="Kip Macy\nkmacy@FreeBSD.org\n2005/06/01"] kp [label="Kristof Provost\nkp@FreeBSD.org\n2015/03/22"] le [label="Lukas Ertl\nle@FreeBSD.org\n2004/02/02"] lidl [label="Kurt Lidl\nlidl@FreeBSD.org\n2015/10/21"] loos [label="Luiz Otavio O Souza\nloos@FreeBSD.org\n2013/07/03"] lstewart [label="Lawrence Stewart\nlstewart@FreeBSD.org\n2008/10/06"] marcel [label="Marcel Moolenaar\nmarcel@FreeBSD.org\n1999/07/03"] marius [label="Marius Strobl\nmarius@FreeBSD.org\n2004/04/17"] markj [label="Mark Johnston\nmarkj@FreeBSD.org\n2012/12/18"] markm [label="Mark Murray\nmarkm@FreeBSD.org\n1995/04/24"] markus [label="Markus Brueffer\nmarkus@FreeBSD.org\n2006/06/01"] matteo [label="Matteo Riondato\nmatteo@FreeBSD.org\n2006/01/18"] mav [label="Alexander Motin\nmav@FreeBSD.org\n2007/04/12"] maxim [label="Maxim Konovalov\nmaxim@FreeBSD.org\n2002/02/07"] mdf [label="Matthew Fleming\nmdf@FreeBSD.org\n2010/06/04"] mdodd [label="Matthew N. Dodd\nmdodd@FreeBSD.org\n1999/07/27"] melifaro [label="Alexander V. Chernikov\nmelifaro@FreeBSD.org\n2011/10/04"] mjacob [label="Matt Jacob\nmjacob@FreeBSD.org\n1997/08/13"] mjg [label="Mateusz Guzik\nmjg@FreeBSD.org\n2012/06/04"] mlaier [label="Max Laier\nmlaier@FreeBSD.org\n2004/02/10"] mmel [label="Michal Meloun\nmmel@FreeBSD.org\n2015/11/01"] monthadar [label="Monthadar Al Jaberi\nmonthadar@FreeBSD.org\n2012/04/02"] mp [label="Mark Peek\nmp@FreeBSD.org\n2001/07/27"] mr [label="Michael Reifenberger\nmr@FreeBSD.org\n2001/09/30"] neel [label="Neel Natu\nneel@FreeBSD.org\n2009/09/20"] netchild [label="Alexander Leidinger\nnetchild@FreeBSD.org\n2005/03/31"] ngie [label="Garrett Cooper\nngie@FreeBSD.org\n2014/07/27"] nork [label="Norikatsu Shigemura\nnork@FreeBSD.org\n2009/06/09"] np [label="Navdeep Parhar\nnp@FreeBSD.org\n2009/06/05"] nwhitehorn [label="Nathan Whitehorn\nnwhitehorn@FreeBSD.org\n2008/07/03"] obrien [label="David E. O'Brien\nobrien@FreeBSD.org\n1996/10/29"] olli [label="Oliver Fromme\nolli@FreeBSD.org\n2008/02/14"] oshogbo [label="Mariusz Zaborski\noshogbo@FreeBSD.org\n2015/04/15"] peadar [label="Peter Edwards\npeadar@FreeBSD.org\n2004/03/08"] peter [label="Peter Wemm\npeter@FreeBSD.org\n1995/07/04"] peterj [label="Peter Jeremy\npeterj@FreeBSD.org\n2012/09/14"] pfg [label="Pedro Giffuni\npfg@FreeBSD.org\n2011/12/01"] philip [label="Philip Paeps\nphilip@FreeBSD.org\n2004/01/21"] phk [label="Poul-Henning Kamp\nphk@FreeBSD.org\n1994/02/21"] pho [label="Peter Holm\npho@FreeBSD.org\n2008/11/16"] pjd [label="Pawel Jakub Dawidek\npjd@FreeBSD.org\n2004/02/02"] pkelsey [label="Patrick Kelsey\pkelsey@FreeBSD.org\n2014/05/29"] pluknet [label="Sergey Kandaurov\npluknet@FreeBSD.org\n2010/10/05"] ps [label="Paul Saab\nps@FreeBSD.org\n2000/02/23"] qingli [label="Qing Li\nqingli@FreeBSD.org\n2005/04/13"] ray [label="Aleksandr Rybalko\nray@FreeBSD.org\n2011/05/25"] rdivacky [label="Roman Divacky\nrdivacky@FreeBSD.org\n2008/03/13"] remko [label="Remko Lodder\nremko@FreeBSD.org\n2007/02/23"] rik [label="Roman Kurakin\nrik@FreeBSD.org\n2003/12/18"] rmacklem [label="Rick Macklem\nrmacklem@FreeBSD.org\n2009/03/27"] rmh [label="Robert Millan\nrmh@FreeBSD.org\n2011/09/18"] rnoland [label="Robert Noland\nrnoland@FreeBSD.org\n2008/09/15"] roberto [label="Ollivier Robert\nroberto@FreeBSD.org\n1995/02/22"] rodrigc [label="Craig Rodrigues\nrodrigc@FreeBSD.org\n2005/05/14"] royger [label="Roger Pau Monne\nroyger@FreeBSD.org\n2013/11/26"] rpaulo [label="Rui Paulo\nrpaulo@FreeBSD.org\n2007/09/25"] rpokala [label="Ravi Pokala\nrpokala@FreeBSD.org\n2015/11/19"] rrs [label="Randall R Stewart\nrrs@FreeBSD.org\n2007/02/08"] rse [label="Ralf S. Engelschall\nrse@FreeBSD.org\n1997/07/31"] rstone [label="Ryan Stone\nrstone@FreeBSD.org\n2010/04/19"] ru [label="Ruslan Ermilov\nru@FreeBSD.org\n1999/05/27"] rwatson [label="Robert N. M. Watson\nrwatson@FreeBSD.org\n1999/12/16"] sam [label="Sam Leffler\nsam@FreeBSD.org\n2002/07/02"] sanpei [label="MIHIRA Sanpei Yoshiro\nsanpei@FreeBSD.org\n2000/06/19"] sbruno [label="Sean Bruno\nsbruno@FreeBSD.org\n2008/08/02"] scf [label="Sean C. Farley\nscf@FreeBSD.org\n2007/06/24"] schweikh [label="Jens Schweikhardt\nschweikh@FreeBSD.org\n2001/04/06"] scottl [label="Scott Long\nscottl@FreeBSD.org\n2000/09/28"] se [label="Stefan Esser\nse@FreeBSD.org\n1994/08/26"] sephe [label="Sepherosa Ziehau\nsephe@FreeBSD.org\n2007/03/28"] sepotvin [label="Stephane E. Potvin\nsepotvin@FreeBSD.org\n2007/02/15"] simon [label="Simon L. Nielsen\nsimon@FreeBSD.org\n2006/03/07"] sjg [label="Simon J. Gerraty\nsjg@FreeBSD.org\n2012/10/23"] skra [label="Svatopluk Kraus\nslm@FreeBSD.org\n2015/10/28"] slm [label="Stephen McConnell\nslm@FreeBSD.org\n2014/05/07"] smh [label="Steven Hartland\nsmh@FreeBSD.org\n2012/11/12"] sobomax [label="Maxim Sobolev\nsobomax@FreeBSD.org\n2001/07/25"] sos [label="Soren Schmidt\nsos@FreeBSD.org\n????/??/??"] sson [label="Stacey Son\nsson@FreeBSD.org\n2008/07/08"] stas [label="Stanislav Sedov\nstas@FreeBSD.org\n2008/08/22"] suz [label="SUZUKI Shinsuke\nsuz@FreeBSD.org\n2002/03/26"] syrinx [label="Shteryana Shopova\nsyrinx@FreeBSD.org\n2006/10/07"] takawata [label="Takanori Watanabe\ntakawata@FreeBSD.org\n2000/07/06"] theraven [label="David Chisnall\ntheraven@FreeBSD.org\n2011/11/11"] thompsa [label="Andrew Thompson\nthompsa@FreeBSD.org\n2005/05/25"] ticso [label="Bernd Walter\nticso@FreeBSD.org\n2002/01/31"] tijl [label="Tijl Coosemans\ntijl@FreeBSD.org\n2010/07/16"] trasz [label="Edward Tomasz Napierala\ntrasz@FreeBSD.org\n2008/08/22"] trhodes [label="Tom Rhodes\ntrhodes@FreeBSD.org\n2002/05/28"] trociny [label="Mikolaj Golub\ntrociny@FreeBSD.org\n2011/03/10"] tuexen [label="Michael Tuexen\ntuexen@FreeBSD.org\n2009/06/06"] tychon [label="Tycho Nightingale\ntychon@FreeBSD.org\n2014/01/21"] ume [label="Hajimu UMEMOTO\nume@FreeBSD.org\n2000/02/26"] uqs [label="Ulrich Spoerlein\nuqs@FreeBSD.org\n2010/01/28"] vangyzen [label="Eric van Gyzen\nvangyzen@FreeBSD.org\n2015/03/08"] vanhu [label="Yvan Vanhullebus\nvanhu@FreeBSD.org\n2008/07/21"] versus [label="Konrad Jankowski\nversus@FreeBSD.org\n2008/10/27"] weongyo [label="Weongyo Jeong\nweongyo@FreeBSD.org\n2007/12/21"] wes [label="Wes Peters\nwes@FreeBSD.org\n1998/11/25"] whu [label="Wei Hu\nwhu@FreeBSD.org\n2015/02/11"] wkoszek [label="Wojciech A. Koszek\nwkoszek@FreeBSD.org\n2006/02/21"] +wma [label="Wojciech Macek\nwma@FreeBSD.org\n2016/01/18"] wollman [label="Garrett Wollman\nwollman@FreeBSD.org\n????/??/??"] wsalamon [label="Wayne Salamon\nwsalamon@FreeBSD.org\n2005/06/25"] yongari [label="Pyun YongHyeon\nyongari@FreeBSD.org\n2004/08/01"] zbb [label="Zbigniew Bodek\nzbb@FreeBSD.org\n2013/09/02"] zec [label="Marko Zec\nzec@FreeBSD.org\n2008/06/22"] zml [label="Zachary Loafman\nzml@FreeBSD.org\n2009/05/27"] zont [label="Andrey Zonov\nzont@FreeBSD.org\n2012/08/21"] # Pseudo target representing rev 1.1 of commit.allow day1 [label="Birth of FreeBSD"] # Here are the mentor/mentee relationships. # Group together all the mentees for a particular mentor. # Keep the list sorted by mentor login. day1 -> jtc day1 -> jkh day1 -> nate day1 -> rgrimes day1 -> alm day1 -> dg adrian -> avos adrian -> lidl adrian -> loos adrian -> monthadar adrian -> ray adrian -> rmh adrian -> sephe ae -> melifaro alc -> davide andre -> qingli anholt -> jkim avg -> art avg -> pluknet avg -> smh bapt -> allanjude bapt -> araujo bapt -> bdrewery benno -> grehan billf -> dougb billf -> gad billf -> jedgar billf -> jhb billf -> shafeeq bmilekic -> csjp bms -> dhartmei bms -> mlaier bms -> thompsa brian -> joe brooks -> bushman brooks -> jamie brooks -> theraven bz -> anchie bz -> jamie bz -> syrinx cognet -> br cognet -> jceel cognet -> kevlo cognet -> ian cognet -> wkoszek +cognet -> wma cognet -> zbb cperciva -> eadler cperciva -> flz cperciva -> randi cperciva -> simon csjp -> bushman das -> kargl das -> rodrigc delphij -> gabor delphij -> rafan delphij -> sephe des -> anholt des -> hmp des -> mike des -> olli des -> ru des -> bapt dds -> versus dfr -> gallatin dfr -> zml dg -> peter dim -> theraven dwmalone -> fanf dwmalone -> peadar dwmalone -> snb ed -> dim ed -> gavin ed -> jilles ed -> rdivacky ed -> uqs eivind -> des eivind -> rwatson emaste -> achim emaste -> rstone emaste -> dteske emaste -> markj emax -> markus fjoe -> versus gallatin -> ticso gavin -> versus gibbs -> mjacob gibbs -> njl gibbs -> royger gibbs -> whu glebius -> mav gnn -> jinmei gnn -> rrs gnn -> ivoras gnn -> vanhu gnn -> lstewart gnn -> np gnn -> davide gnn -> arybchik gnn -> erj gnn -> kp gnn -> jtl grehan -> bryanv grog -> edwin grog -> le grog -> peterj imp -> akiyama imp -> ambrisko imp -> andrew imp -> bmah imp -> bruno imp -> dmlb imp -> emax imp -> furuta imp -> joe imp -> jon imp -> keichii imp -> mb imp -> mr imp -> neel imp -> non imp -> nork imp -> onoe imp -> remko imp -> rik imp -> rink imp -> sanpei imp -> shiba imp -> takawata imp -> toshi imp -> uch jake -> bms jake -> gordon jake -> harti jake -> jeff jake -> kmacy jake -> robert jake -> yongari jb -> sson jdp -> fjoe jfv -> erj jhb -> arr jhb -> avg jhb -> jch jhb -> jeff jhb -> kbyanc jhb -> peterj jhb -> pfg jhb -> rnoland jhb -> rpokala jimharris -> carl jkh -> dfr jkh -> gj jkh -> grog jkh -> imp jkh -> jlemon jkh -> joerg jkh -> jwd jkh -> msmith jkh -> murray jkh -> phk jkh -> wes jkh -> yar jkoshy -> kaiw jkoshy -> fabient jkoshy -> rstone jlemon -> bmilekic jlemon -> brooks jmallett -> pkelsey jmmv -> ngie joerg -> brian joerg -> eik joerg -> jmg joerg -> le joerg -> netchild joerg -> schweikh julian -> glebius julian -> davidxu julian -> archie julian -> adrian julian -> zec julian -> mp kan -> kib ken -> asomers ken -> slm kib -> ae kib -> dchagin kib -> gjb kib -> jah kib -> jlh kib -> jpaetzel kib -> lulf kib -> melifaro kib -> mmel kib -> pho kib -> pluknet kib -> rdivacky kib -> rmacklem kib -> rmh kib -> skra kib -> stas kib -> tijl kib -> trociny kib -> vangyzen kib -> zont kmacy -> lstewart marcel -> allanjude marcel -> art marcel -> arun marcel -> marius marcel -> nwhitehorn marcel -> sjg markj -> cem markm -> jasone markm -> sheldonh mav -> ae mdf -> gleb mdodd -> jake mike -> das mlaier -> benjsc mlaier -> dhartmei mlaier -> thompsa mlaier -> eri msmith -> cokane msmith -> jasone msmith -> scottl murray -> delphij mux -> cognet mux -> dumbbell netchild -> ariff njl -> marks njl -> philip njl -> rpaulo njl -> sepotvin nwhitehorn -> andreast nwhitehorn -> jhibbits obrien -> benno obrien -> groudier obrien -> gshapiro obrien -> kan obrien -> sam peter -> asmodai peter -> jayanth peter -> ps philip -> benl philip -> ed philip -> jls philip -> matteo philip -> uqs philip -> kp phk -> jkoshy phk -> mux pjd -> kib pjd -> lulf pjd -> oshogbo pjd -> smh pjd -> trociny rgrimes -> markm rmacklem -> jwd royger -> whu rpaulo -> avg rpaulo -> bschmidt rpaulo -> dim rpaulo -> jmmv rpaulo -> lidl rpaulo -> ngie rrs -> brucec rrs -> jchandra rrs -> tuexen rstone -> markj ru -> ceri ru -> cjc ru -> eik ru -> maxim ru -> sobomax rwatson -> adrian rwatson -> antoine rwatson -> bmah rwatson -> brueffer rwatson -> bz rwatson -> cperciva rwatson -> emaste rwatson -> gnn rwatson -> jh rwatson -> jonathan rwatson -> kensmith rwatson -> kmacy rwatson -> linimon rwatson -> rmacklem rwatson -> shafeeq rwatson -> tmm rwatson -> trasz rwatson -> trhodes rwatson -> wsalamon rodrigc -> araujo sam -> andre sam -> benjsc sam -> sephe sbruno -> hiren sbruno -> jimharris schweikh -> dds scottl -> achim scottl -> jimharris scottl -> pjd scottl -> sah scottl -> sbruno scottl -> slm scottl -> yongari sheldonh -> dwmalone sheldonh -> iedowse shin -> ume simon -> benl sos -> marcel thompsa -> weongyo thompsa -> eri trasz -> jh trasz -> mjg ume -> jinmei ume -> suz ume -> tshiozak wes -> scf wkoszek -> jceel wollman -> gad zml -> mdf zml -> zack } Index: projects/release-pkg/share/misc/organization.dot =================================================================== --- projects/release-pkg/share/misc/organization.dot (revision 294447) +++ projects/release-pkg/share/misc/organization.dot (revision 294448) @@ -1,103 +1,103 @@ # $FreeBSD$ # This file is meant to show the infrastructural organization of the # FreeBSD Project; what kind of teams we have and how they relate to # each other. # For a detailed description of the responsibilities and duties of the listed # teams, please see our Administration page at # http://www.freebsd.org/administration.html . # # The graphical output can be generated from this file with the following # command: # $ dot -T png -o file.png organization.dot # # The dot binary is part of the graphics/graphviz port. digraph org { node [color=lightblue2, style=filled, bgcolor=black]; # Meta-categories go here _devel [label="FreeBSD Developers"] _admin [label="FreeBSD Infrastructure Administrators"] _misc [label="Miscellaneous Hats"] # Development teams go here alphabetically sorted core [label="Core Team\ncore@FreeBSD.org\nbapt, emaste, gavin,\nglebius, gnn, hrs,\npeter, rwatson, theraven"] coresecretary [label="Core Team Secretary\ncore-secretary@FreeBSD.org\nmatthew"] doccommitters [label="Doc/www Committers\ndoc-committers@FreeBSD.org"] doceng [label="Documentation Engineering Team\ndoceng@FreeBSD.org\ngjb, blackend,\ngabor, hrs"] portscommitters [label="Ports Committers\nports-committers@FreeBSD.org"] -portmgr [label="Port Management Team\nportmgr@FreeBSD.org\nantoine, bapt, bdrewery,\nerwin, mat, swills"] +portmgr [label="Port Management Team\nportmgr@FreeBSD.org\nantoine, bapt, bdrewery,\nerwin, mat, swills,\nmiwi"] portmgrsecretary [label="Port Management Team Secretary\nportmgr-secretary@FreeBSD.org\nculot"] re [label="Primary Release Engineering Team\nre@FreeBSD.org\nkib, blackend, jpaetzel, hrs, kensmith"] secteam [label="Security Team\nsecteam@FreeBSD.org\nsimon, qingli, delphij,\nremko, philip, stas, cperciva,\ncsjp, rwatson, miwi, bz"] portssecteam [label="Ports Security Team\nports-secteam@FreeBSD.org\ndelphij, eadler, feld, jgh, miwi, rea, sbz, simon, swills, zi"] secteamsecretary [label="Security Team Secretary\nsecteam-secretary@FreeBSD.org\nremko"] securityofficer [label="Security Officer Team\nsecurity-officer@FreeBSD.org\ncperciva, simon, nectar"] srccommitters [label="Src Committers\nsrc-committers@FreeBSD.org"] # Admin teams go here alphabetically sorted accounts [label="Accounts Team\naccounts@FreeBSD.org\nmarkm, simon, kensmith,\ndhw"] backups [label="Backup Administrators\nbackups@FreeBSD.org\nsimon, kensmith,\ndhw"] bugmeister [label="Bugmeister Team\nbugmeister@FreeBSD.org\neadler, gavin, gonzo"] clusteradm [label="Cluster Administrators\nclusteradm@FreeBSD.org\nbrd, simon, ps,\nkensmith, peter"] cvsupmaster [label="CVSup Mirror Site Coordinators\ncvsup-master@FreeBSD.org\nkuriyama, jdp,\nkensmith"] dnsadm [label="DNS Administrators\ndnsadm@FreeBSD.org\nbillf, dg, ps,\nkensmith, peter"] mirroradmin [label="FTP/WWW Mirror Site Coordinators\nmirror-admin@FreeBSD.org\nkuriyama, kensmith"] ncvs [label="CVS src Repository Managers\nncvs@FreeBSD.org\njoe, kuriyama, markm,\nsimon, peter"] perforceadmin [label="Perforce Repository Administrators\nperforce-admin@FreeBSD.org\nscottl, kensmith, gordon,\nrwatson, peter, dhw"] postmaster [label="Postmaster Team\npostmaster@FreeBSD.org\njmb, brd, sahil, dhw"] refadm [label="Reference Systems Administrators\nrefadm@FreeBSD.org\njake, billf, markm, simon,\nobrien, ps, kensmith,\npeter, dhw"] webmaster [label="Webmaster Team\nwebmaster@FreeBSD.org\nnik, kuriyama, simon,\njesusr, wosch"] # Misc hats go here alphabetically sorted donations [label="Donations Team\ndonations@FreeBSD.org\ngjb, wilko, gahr, pgolluci,\nobrien, trhodes, ds,\nrwatson"] marketing [label="Marketing Team\nmarketing@FreeBSD.org\nSteven Beedle, Denise Ebery, deb,\njkoshy, Dru Lavigne, mwlucas, imp,\nKris Moore, murray, mattt,\nJeremy C. Reed, rwatson"] vendorrelations [label="Vendor Relations\nvendor-relations@FreeBSD.org\ncore, FreeBSD Foundation"] # Here are the team relationships. # Group together all the entries for the superior team. # Keep the list sorted by the superior team entry. _admin -> accounts _admin -> backups _admin -> bugmeister _admin -> clusteradm _admin -> ncvs _admin -> cvsupmaster _admin -> dnsadm _admin -> mirroradmin _admin -> perforceadmin _admin -> refadm _admin -> postmaster _admin -> webmaster _devel -> core _misc -> donations _misc -> marketing _misc -> vendorrelations core -> coresecretary core -> doceng core -> portmgr core -> re core -> securityofficer core -> srccommitters doceng -> doccommitters portmgr -> portmgrsecretary portmgr -> portscommitters securityofficer -> secteam securityofficer -> portssecteam secteam -> secteamsecretary } Index: projects/release-pkg/share =================================================================== --- projects/release-pkg/share (revision 294447) +++ projects/release-pkg/share (revision 294448) Property changes on: projects/release-pkg/share ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share:r294408-294447 Index: projects/release-pkg/sys/arm/arm/gic.c =================================================================== --- projects/release-pkg/sys/arm/arm/gic.c (revision 294447) +++ projects/release-pkg/sys/arm/arm/gic.c (revision 294448) @@ -1,1163 +1,1165 @@ /*- * Copyright (c) 2011 The FreeBSD Foundation * All rights reserved. * * Developed by Damjan Marion * * Based on OMAP4 GIC code by Ben Gray * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ARM_INTRNG #include #endif #include #include #include #include #include #include #include #ifdef ARM_INTRNG #include "pic_if.h" #endif #define GIC_DEBUG_SPURIOUS /* We are using GICv2 register naming */ /* Distributor Registers */ #define GICD_CTLR 0x000 /* v1 ICDDCR */ #define GICD_TYPER 0x004 /* v1 ICDICTR */ #define GICD_IIDR 0x008 /* v1 ICDIIDR */ #define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */ #define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */ #define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */ #define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */ #define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */ #define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */ #define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */ #define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */ #define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */ #define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */ /* CPU Registers */ #define GICC_CTLR 0x0000 /* v1 ICCICR */ #define GICC_PMR 0x0004 /* v1 ICCPMR */ #define GICC_BPR 0x0008 /* v1 ICCBPR */ #define GICC_IAR 0x000C /* v1 ICCIAR */ #define GICC_EOIR 0x0010 /* v1 ICCEOIR */ #define GICC_RPR 0x0014 /* v1 ICCRPR */ #define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ #define GICC_ABPR 0x001C /* v1 ICCABPR */ #define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ #define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */ #define GIC_LAST_SGI 15 #define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */ #define GIC_LAST_PPI 31 /* core) peripheral interrupts. */ #define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */ /* First bit is a polarity bit (0 - low, 1 - high) */ #define GICD_ICFGR_POL_LOW (0 << 0) #define GICD_ICFGR_POL_HIGH (1 << 0) #define GICD_ICFGR_POL_MASK 0x1 /* Second bit is a trigger bit (0 - level, 1 - edge) */ #define GICD_ICFGR_TRIG_LVL (0 << 1) #define GICD_ICFGR_TRIG_EDGE (1 << 1) #define GICD_ICFGR_TRIG_MASK 0x2 #ifndef GIC_DEFAULT_ICFGR_INIT #define GIC_DEFAULT_ICFGR_INIT 0x00000000 #endif #ifdef ARM_INTRNG static u_int gic_irq_cpu; static int arm_gic_intr(void *); static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc); #endif struct arm_gic_softc { device_t gic_dev; #ifdef ARM_INTRNG void * gic_intrhand; struct intr_irqsrc ** gic_irqs; #endif struct resource * gic_res[3]; bus_space_tag_t gic_c_bst; bus_space_tag_t gic_d_bst; bus_space_handle_t gic_c_bsh; bus_space_handle_t gic_d_bsh; uint8_t ver; struct mtx mutex; uint32_t nirqs; #ifdef GIC_DEBUG_SPURIOUS uint32_t last_irq[MAXCPU]; #endif }; static struct resource_spec arm_gic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ #ifdef ARM_INTRNG { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ #endif { -1, 0 } }; static struct arm_gic_softc *gic_sc = NULL; #define gic_c_read_4(_sc, _reg) \ bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) #define gic_c_write_4(_sc, _reg, _val) \ bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) #define gic_d_read_4(_sc, _reg) \ bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) #define gic_d_write_1(_sc, _reg, _val) \ bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) #define gic_d_write_4(_sc, _reg, _val) \ bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) #ifndef ARM_INTRNG static int gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol); static void gic_post_filter(void *); #endif static struct ofw_compat_data compat_data[] = { {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */ {"arm,gic-400", true}, {"arm,cortex-a15-gic", true}, {"arm,cortex-a9-gic", true}, {"arm,cortex-a7-gic", true}, {"arm,arm11mp-gic", true}, {"brcm,brahma-b15-gic", true}, {NULL, false} }; static int arm_gic_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "ARM Generic Interrupt Controller"); return (BUS_PROBE_DEFAULT); } #ifdef ARM_INTRNG static inline void gic_irq_unmask(struct arm_gic_softc *sc, u_int irq) { gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); } static inline void gic_irq_mask(struct arm_gic_softc *sc, u_int irq) { gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); } #endif #ifdef SMP #ifdef ARM_INTRNG static void arm_gic_init_secondary(device_t dev) { struct arm_gic_softc *sc = device_get_softc(dev); struct intr_irqsrc *isrc; u_int irq; for (irq = 0; irq < sc->nirqs; irq += 4) gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0); /* Set all the interrupts to be in Group 0 (secure) */ for (irq = 0; irq < sc->nirqs; irq += 32) { gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0); } /* Enable CPU interface */ gic_c_write_4(sc, GICC_CTLR, 1); /* Set priority mask register. */ gic_c_write_4(sc, GICC_PMR, 0xff); /* Enable interrupt distribution */ gic_d_write_4(sc, GICD_CTLR, 0x01); /* Unmask attached SGI interrupts. */ for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) { isrc = sc->gic_irqs[irq]; if (isrc != NULL && isrc->isrc_handlers != 0) { CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); gic_irq_unmask(sc, irq); } } /* Unmask attached PPI interrupts. */ for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) { isrc = sc->gic_irqs[irq]; if (isrc == NULL || isrc->isrc_handlers == 0) continue; if (isrc->isrc_flags & INTR_ISRCF_BOUND) { if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu)) gic_irq_unmask(sc, irq); } else { CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); gic_irq_unmask(sc, irq); } } } #else static void arm_gic_init_secondary(device_t dev) { struct arm_gic_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->nirqs; i += 4) gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); /* Set all the interrupts to be in Group 0 (secure) */ for (i = 0; i < sc->nirqs; i += 32) { gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); } /* Enable CPU interface */ gic_c_write_4(sc, GICC_CTLR, 1); /* Set priority mask register. */ gic_c_write_4(sc, GICC_PMR, 0xff); /* Enable interrupt distribution */ gic_d_write_4(sc, GICD_CTLR, 0x01); /* * Activate the timer interrupts: virtual, secure, and non-secure. */ gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F))); gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F))); } #endif /* ARM_INTRNG */ #endif /* SMP */ #ifndef ARM_INTRNG int gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, int *trig, int *pol) { static u_int num_intr_cells; static phandle_t self; struct ofw_compat_data *ocd; if (self == 0) { for (ocd = compat_data; ocd->ocd_str != NULL; ocd++) { if (fdt_is_compatible(iparent, ocd->ocd_str)) { self = iparent; break; } } } if (self != iparent) return (ENXIO); if (num_intr_cells == 0) { if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &num_intr_cells, sizeof(num_intr_cells)) == -1) { num_intr_cells = 1; } } if (num_intr_cells == 1) { *interrupt = fdt32_to_cpu(intr[0]); *trig = INTR_TRIGGER_CONFORM; *pol = INTR_POLARITY_CONFORM; } else { if (fdt32_to_cpu(intr[0]) == 0) *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI; else *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI; /* * In intr[2], bits[3:0] are trigger type and level flags. * 1 = low-to-high edge triggered * 2 = high-to-low edge triggered * 4 = active high level-sensitive * 8 = active low level-sensitive - * The hardware only supports active-high-level or rising-edge. + * The hardware only supports active-high-level or rising-edge + * for SPIs */ - if (fdt32_to_cpu(intr[2]) & 0x0a) { + if (*interrupt >= GIC_FIRST_SPI && + fdt32_to_cpu(intr[2]) & 0x0a) { printf("unsupported trigger/polarity configuration " "0x%02x\n", fdt32_to_cpu(intr[2]) & 0x0f); } *pol = INTR_POLARITY_CONFORM; if (fdt32_to_cpu(intr[2]) & 0x03) *trig = INTR_TRIGGER_EDGE; else *trig = INTR_TRIGGER_LEVEL; } return (0); } #endif #ifdef ARM_INTRNG static inline intptr_t gic_xref(device_t dev) { #ifdef FDT return (OF_xref_from_node(ofw_bus_get_node(dev))); #else return (0); #endif } #endif static int arm_gic_attach(device_t dev) { struct arm_gic_softc *sc; int i; uint32_t icciidr; #ifdef ARM_INTRNG phandle_t pxref; intptr_t xref = gic_xref(dev); #endif if (gic_sc) return (ENXIO); sc = device_get_softc(dev); if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->gic_dev = dev; gic_sc = sc; /* Initialize mutex */ mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); /* Distributor Interface */ sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]); /* CPU Interface */ sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); /* Disable interrupt forwarding to the CPU interface */ gic_d_write_4(sc, GICD_CTLR, 0x00); /* Get the number of interrupts */ sc->nirqs = gic_d_read_4(sc, GICD_TYPER); sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); #ifdef ARM_INTRNG sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF, M_WAITOK | M_ZERO); #else /* Set up function pointers */ arm_post_filter = gic_post_filter; arm_config_irq = gic_config_irq; #endif icciidr = gic_c_read_4(sc, GICC_IIDR); device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, (icciidr & 0xfff), sc->nirqs); /* Set all global interrupts to be level triggered, active low. */ for (i = 32; i < sc->nirqs; i += 16) { gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT); } /* Disable all interrupts. */ for (i = 32; i < sc->nirqs; i += 32) { gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF); } for (i = 0; i < sc->nirqs; i += 4) { gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24); } /* Set all the interrupts to be in Group 0 (secure) */ for (i = 0; i < sc->nirqs; i += 32) { gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); } /* Enable CPU interface */ gic_c_write_4(sc, GICC_CTLR, 1); /* Set priority mask register. */ gic_c_write_4(sc, GICC_PMR, 0xff); /* Enable interrupt distribution */ gic_d_write_4(sc, GICD_CTLR, 0x01); #ifndef ARM_INTRNG return (0); #else /* * Now, when everything is initialized, it's right time to * register interrupt controller to interrupt framefork. */ if (intr_pic_register(dev, xref) != 0) { device_printf(dev, "could not register PIC\n"); goto cleanup; } /* * Controller is root if: * - doesn't have interrupt parent * - his interrupt parent is this controller */ pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); if (pxref == 0 || xref == pxref) { if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { device_printf(dev, "could not set PIC as a root\n"); intr_pic_unregister(dev, xref); goto cleanup; } } else { if (sc->gic_res[2] == NULL) { device_printf(dev, "not root PIC must have defined interrupt\n"); intr_pic_unregister(dev, xref); goto cleanup; } if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { device_printf(dev, "could not setup irq handler\n"); intr_pic_unregister(dev, xref); goto cleanup; } } OF_device_register_xref(xref, dev); return (0); cleanup: /* * XXX - not implemented arm_gic_detach() should be called ! */ if (sc->gic_irqs != NULL) free(sc->gic_irqs, M_DEVBUF); bus_release_resources(dev, arm_gic_spec, sc->gic_res); return(ENXIO); #endif } #ifdef ARM_INTRNG static int arm_gic_intr(void *arg) { struct arm_gic_softc *sc = arg; struct intr_irqsrc *isrc; uint32_t irq_active_reg, irq; struct trapframe *tf; irq_active_reg = gic_c_read_4(sc, GICC_IAR); irq = irq_active_reg & 0x3FF; /* * 1. We do EOI here because recent read value from active interrupt * register must be used for it. Another approach is to save this * value into associated interrupt source. * 2. EOI must be done on same CPU where interrupt has fired. Thus * we must ensure that interrupted thread does not migrate to * another CPU. * 3. EOI cannot be delayed by any preemption which could happen on * critical_exit() used in MI intr code, when interrupt thread is * scheduled. See next point. * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during * an action and any use of critical_exit() could break this * assumption. See comments within smp_rendezvous_action(). * 5. We always return FILTER_HANDLED as this is an interrupt * controller dispatch function. Otherwise, in cascaded interrupt * case, the whole interrupt subtree would be masked. */ if (irq >= sc->nirqs) { #ifdef GIC_DEBUG_SPURIOUS device_printf(sc->gic_dev, "Spurious interrupt detected: last irq: %d on CPU%d\n", sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid)); #endif return (FILTER_HANDLED); } tf = curthread->td_intr_frame; dispatch_irq: isrc = sc->gic_irqs[irq]; if (isrc == NULL) { device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq); gic_irq_mask(sc, irq); gic_c_write_4(sc, GICC_EOIR, irq_active_reg); goto next_irq; } /* * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement * as compiler complains that comparing u_int >= 0 is always true. */ if (irq <= GIC_LAST_SGI) { #ifdef SMP /* Call EOI for all IPI before dispatch. */ gic_c_write_4(sc, GICC_EOIR, irq_active_reg); intr_ipi_dispatch(isrc, tf); goto next_irq; #else device_printf(sc->gic_dev, "SGI %u on UP system detected\n", irq - GIC_FIRST_SGI); gic_c_write_4(sc, GICC_EOIR, irq_active_reg); goto next_irq; #endif } #ifdef GIC_DEBUG_SPURIOUS sc->last_irq[PCPU_GET(cpuid)] = irq; #endif if (isrc->isrc_trig == INTR_TRIGGER_EDGE) gic_c_write_4(sc, GICC_EOIR, irq_active_reg); intr_irq_dispatch(isrc, tf); next_irq: arm_irq_memory_barrier(irq); irq_active_reg = gic_c_read_4(sc, GICC_IAR); irq = irq_active_reg & 0x3FF; if (irq < sc->nirqs) goto dispatch_irq; return (FILTER_HANDLED); } static int gic_attach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) { const char *name; /* * 1. The link between ISRC and controller must be set atomically. * 2. Just do things only once in rare case when consumers * of shared interrupt came here at the same moment. */ mtx_lock_spin(&sc->mutex); if (sc->gic_irqs[irq] != NULL) { mtx_unlock_spin(&sc->mutex); return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST); } sc->gic_irqs[irq] = isrc; isrc->isrc_data = irq; mtx_unlock_spin(&sc->mutex); name = device_get_nameunit(sc->gic_dev); if (irq <= GIC_LAST_SGI) intr_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI); else if (irq <= GIC_LAST_PPI) intr_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI); else intr_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI); return (0); } static int gic_detach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) { mtx_lock_spin(&sc->mutex); if (sc->gic_irqs[irq] != isrc) { mtx_unlock_spin(&sc->mutex); return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL); } sc->gic_irqs[irq] = NULL; isrc->isrc_data = 0; mtx_unlock_spin(&sc->mutex); intr_irq_set_name(isrc, ""); return (0); } static void gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, enum intr_polarity pol) { uint32_t reg; uint32_t mask; if (irq < GIC_FIRST_SPI) return; mtx_lock_spin(&sc->mutex); reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); mask = (reg >> 2*(irq % 16)) & 0x3; if (pol == INTR_POLARITY_LOW) { mask &= ~GICD_ICFGR_POL_MASK; mask |= GICD_ICFGR_POL_LOW; } else if (pol == INTR_POLARITY_HIGH) { mask &= ~GICD_ICFGR_POL_MASK; mask |= GICD_ICFGR_POL_HIGH; } if (trig == INTR_TRIGGER_LEVEL) { mask &= ~GICD_ICFGR_TRIG_MASK; mask |= GICD_ICFGR_TRIG_LVL; } else if (trig == INTR_TRIGGER_EDGE) { mask &= ~GICD_ICFGR_TRIG_MASK; mask |= GICD_ICFGR_TRIG_EDGE; } /* Set mask */ reg = reg & ~(0x3 << 2*(irq % 16)); reg = reg | (mask << 2*(irq % 16)); gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); mtx_unlock_spin(&sc->mutex); } static int gic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus) { uint32_t cpu, end, mask; end = min(mp_ncpus, 8); for (cpu = end; cpu < MAXCPU; cpu++) if (CPU_ISSET(cpu, cpus)) return (EINVAL); for (mask = 0, cpu = 0; cpu < end; cpu++) if (CPU_ISSET(cpu, cpus)) mask |= 1 << cpu; gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask); return (0); } static int gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp) { switch (type) { case INTR_IRQ_NSPC_PLAIN: *irqp = num; return (*irqp < sc->nirqs ? 0 : EINVAL); case INTR_IRQ_NSPC_IRQ: *irqp = num + GIC_FIRST_PPI; return (*irqp < sc->nirqs ? 0 : EINVAL); case INTR_IRQ_NSPC_IPI: *irqp = num + GIC_FIRST_SGI; return (*irqp < GIC_LAST_SGI ? 0 : EINVAL); default: return (EINVAL); } } static int gic_map_nspc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) { int error; error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num, irqp); if (error != 0) return (error); return (gic_attach_isrc(sc, isrc, *irqp)); } #ifdef FDT static int gic_map_fdt(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) { u_int irq, tripol; enum intr_trigger trig; enum intr_polarity pol; int error; if (isrc->isrc_ncells == 1) { irq = isrc->isrc_cells[0]; pol = INTR_POLARITY_CONFORM; trig = INTR_TRIGGER_CONFORM; } else if (isrc->isrc_ncells == 3) { if (isrc->isrc_cells[0] == 0) irq = isrc->isrc_cells[1] + GIC_FIRST_SPI; else irq = isrc->isrc_cells[1] + GIC_FIRST_PPI; /* * In intr[2], bits[3:0] are trigger type and level flags. * 1 = low-to-high edge triggered * 2 = high-to-low edge triggered * 4 = active high level-sensitive * 8 = active low level-sensitive * The hardware only supports active-high-level or rising-edge. */ tripol = isrc->isrc_cells[2]; if (tripol & 0x0a) { device_printf(sc->gic_dev, "unsupported trigger/polarity configuration " "0x%02x\n", tripol & 0x0f); } pol = INTR_POLARITY_CONFORM; if (tripol & 0x03) trig = INTR_TRIGGER_EDGE; else trig = INTR_TRIGGER_LEVEL; } else return (EINVAL); if (irq >= sc->nirqs) return (EINVAL); error = gic_attach_isrc(sc, isrc, irq); if (error != 0) return (error); isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; isrc->isrc_nspc_num = irq; isrc->isrc_trig = trig; isrc->isrc_pol = pol; *irqp = irq; return (0); } #endif static int arm_gic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) { struct arm_gic_softc *sc = device_get_softc(dev); u_int irq; int error; if (isrc->isrc_type == INTR_ISRCT_NAMESPACE) error = gic_map_nspc(sc, isrc, &irq); #ifdef FDT else if (isrc->isrc_type == INTR_ISRCT_FDT) error = gic_map_fdt(sc, isrc, &irq); #endif else return (EINVAL); if (error == 0) *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE; return (error); } static void arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); u_int irq = isrc->isrc_data; if (isrc->isrc_trig == INTR_TRIGGER_CONFORM) isrc->isrc_trig = INTR_TRIGGER_LEVEL; /* * XXX - In case that per CPU interrupt is going to be enabled in time * when SMP is already started, we need some IPI call which * enables it on others CPUs. Further, it's more complicated as * pic_enable_source() and pic_disable_source() should act on * per CPU basis only. Thus, it should be solved here somehow. */ if (isrc->isrc_flags & INTR_ISRCF_PERCPU) CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol); arm_gic_bind(dev, isrc); } static void arm_gic_enable_source(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); u_int irq = isrc->isrc_data; arm_irq_memory_barrier(irq); gic_irq_unmask(sc, irq); } static void arm_gic_disable_source(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); u_int irq = isrc->isrc_data; gic_irq_mask(sc, irq); } static int arm_gic_unregister(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); u_int irq = isrc->isrc_data; return (gic_detach_isrc(sc, isrc, irq)); } static void arm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); arm_gic_disable_source(dev, isrc); gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); } static void arm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { arm_irq_memory_barrier(0); arm_gic_enable_source(dev, isrc); } static void arm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); /* EOI for edge-triggered done earlier. */ if (isrc->isrc_trig == INTR_TRIGGER_EDGE) return; arm_irq_memory_barrier(0); gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); } static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); uint32_t irq = isrc->isrc_data; if (irq < GIC_FIRST_SPI) return (EINVAL); if (CPU_EMPTY(&isrc->isrc_cpu)) { gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); } return (gic_bind(sc, irq, &isrc->isrc_cpu)); } #ifdef SMP static void arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus) { struct arm_gic_softc *sc = device_get_softc(dev); uint32_t irq, val = 0, i; irq = isrc->isrc_data; for (i = 0; i < MAXCPU; i++) if (CPU_ISSET(i, &cpus)) val |= 1 << (16 + i); gic_d_write_4(sc, GICD_SGIR(0), val | irq); } #endif #else static int arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) { uint32_t active_irq; active_irq = gic_c_read_4(sc, GICC_IAR); /* * Immediatly EOIR the SGIs, because doing so requires the other * bits (ie CPU number), not just the IRQ number, and we do not * have this information later. */ if ((active_irq & 0x3ff) <= GIC_LAST_SGI) gic_c_write_4(sc, GICC_EOIR, active_irq); active_irq &= 0x3FF; if (active_irq == 0x3FF) { if (last_irq == -1) device_printf(sc->gic_dev, "Spurious interrupt detected\n"); return -1; } return active_irq; } static int arm_gic_config(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol) { struct arm_gic_softc *sc = device_get_softc(dev); uint32_t reg; uint32_t mask; /* Function is public-accessible, so validate input arguments */ if ((irq < 0) || (irq >= sc->nirqs)) goto invalid_args; if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && (trig != INTR_TRIGGER_CONFORM)) goto invalid_args; if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) && (pol != INTR_POLARITY_CONFORM)) goto invalid_args; mtx_lock_spin(&sc->mutex); reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); mask = (reg >> 2*(irq % 16)) & 0x3; if (pol == INTR_POLARITY_LOW) { mask &= ~GICD_ICFGR_POL_MASK; mask |= GICD_ICFGR_POL_LOW; } else if (pol == INTR_POLARITY_HIGH) { mask &= ~GICD_ICFGR_POL_MASK; mask |= GICD_ICFGR_POL_HIGH; } if (trig == INTR_TRIGGER_LEVEL) { mask &= ~GICD_ICFGR_TRIG_MASK; mask |= GICD_ICFGR_TRIG_LVL; } else if (trig == INTR_TRIGGER_EDGE) { mask &= ~GICD_ICFGR_TRIG_MASK; mask |= GICD_ICFGR_TRIG_EDGE; } /* Set mask */ reg = reg & ~(0x3 << 2*(irq % 16)); reg = reg | (mask << 2*(irq % 16)); gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); mtx_unlock_spin(&sc->mutex); return (0); invalid_args: device_printf(dev, "gic_config_irg, invalid parameters\n"); return (EINVAL); } static void arm_gic_mask(device_t dev, int irq) { struct arm_gic_softc *sc = device_get_softc(dev); gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */ } static void arm_gic_unmask(device_t dev, int irq) { struct arm_gic_softc *sc = device_get_softc(dev); if (irq > GIC_LAST_SGI) arm_irq_memory_barrier(irq); gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); } #ifdef SMP static void arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) { struct arm_gic_softc *sc = device_get_softc(dev); uint32_t val = 0, i; for (i = 0; i < MAXCPU; i++) if (CPU_ISSET(i, &cpus)) val |= 1 << (16 + i); gic_d_write_4(sc, GICD_SGIR(0), val | ipi); } static int arm_gic_ipi_read(device_t dev, int i) { if (i != -1) { /* * The intr code will automagically give the frame pointer * if the interrupt argument is 0. */ if ((unsigned int)i > 16) return (0); return (i); } return (0x3ff); } static void arm_gic_ipi_clear(device_t dev, int ipi) { /* no-op */ } #endif static void gic_post_filter(void *arg) { struct arm_gic_softc *sc = gic_sc; uintptr_t irq = (uintptr_t) arg; if (irq > GIC_LAST_SGI) arm_irq_memory_barrier(irq); gic_c_write_4(sc, GICC_EOIR, irq); } static int gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol) { return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol)); } void arm_mask_irq(uintptr_t nb) { arm_gic_mask(gic_sc->gic_dev, nb); } void arm_unmask_irq(uintptr_t nb) { arm_gic_unmask(gic_sc->gic_dev, nb); } int arm_get_next_irq(int last_irq) { return (arm_gic_next_irq(gic_sc, last_irq)); } #ifdef SMP void intr_pic_init_secondary(void) { arm_gic_init_secondary(gic_sc->gic_dev); } void pic_ipi_send(cpuset_t cpus, u_int ipi) { arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi); } int pic_ipi_read(int i) { return (arm_gic_ipi_read(gic_sc->gic_dev, i)); } void pic_ipi_clear(int ipi) { arm_gic_ipi_clear(gic_sc->gic_dev, ipi); } #endif #endif /* ARM_INTRNG */ static device_method_t arm_gic_methods[] = { /* Device interface */ DEVMETHOD(device_probe, arm_gic_probe), DEVMETHOD(device_attach, arm_gic_attach), #ifdef ARM_INTRNG /* Interrupt controller interface */ DEVMETHOD(pic_disable_source, arm_gic_disable_source), DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), DEVMETHOD(pic_enable_source, arm_gic_enable_source), DEVMETHOD(pic_post_filter, arm_gic_post_filter), DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), DEVMETHOD(pic_register, arm_gic_register), DEVMETHOD(pic_unregister, arm_gic_unregister), #ifdef SMP DEVMETHOD(pic_bind, arm_gic_bind), DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), #endif #endif { 0, 0 } }; static driver_t arm_gic_driver = { "gic", arm_gic_methods, sizeof(struct arm_gic_softc), }; static devclass_t arm_gic_devclass; EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: projects/release-pkg/sys/arm/conf/ARMADA38X =================================================================== --- projects/release-pkg/sys/arm/conf/ARMADA38X (nonexistent) +++ projects/release-pkg/sys/arm/conf/ARMADA38X (revision 294448) @@ -0,0 +1,84 @@ +# +# Kernel configuration for Marvell Armada38x +# +# $FreeBSD$ +# + +include "../mv/armada38x/std.armada38x" +include "std.armv6" + +ident ARMADA38X + +options SOC_MV_ARMADA38X + +makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols +makeoptions WERROR="-Werror" + +options MD_ROOT +#makeoptions MFS_IMAGE=/path/to/miniroot +#options ROOTDEVNAME=\"ufs:md0\" +options ROOTDEVNAME=\"/dev/da0s1a\" + +options SCHED_ULE # ULE scheduler +#options SCHED_4BSD # 4BSD scheduler + +options SMP + +# Debugging +#options DEBUG +#options VERBOSE_SYSINIT +options ALT_BREAK_TO_DEBUGGER +options DDB +#options GDB +#options DIAGNOSTIC +options INVARIANTS # Enable calls of extra sanity checking +options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS +options KDB +options KDB_TRACE +#options WITNESS # Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed +#options WITNESS_KDB +#options BOOTVERBOSE + +# Pseudo devices +device random +device pty +device loop +device md + +# Serial ports +device uart +device uart_ns8250 + +# Network +device ether +device vlan +device mii +device bpf +device re + +# PCI +device pci + +# Interrupt controllers +device gic + +# Timers +device mpcore_timer + +# USB +device usb +device ehci +device umass +device scbus +device pass +device da + +# I2C +device iic +device iicbus + +#FDT +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=armada-388-gp.dts Property changes on: projects/release-pkg/sys/arm/conf/ARMADA38X ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/release-pkg/sys/arm/conf/DB-78XXX =================================================================== --- projects/release-pkg/sys/arm/conf/DB-78XXX (revision 294447) +++ projects/release-pkg/sys/arm/conf/DB-78XXX (revision 294448) @@ -1,96 +1,99 @@ # # Custom kernel for Marvell DB-78xx boards. # # $FreeBSD$ # ident DB-88F78XX include "std.arm" include "../mv/discovery/std.db78xxx" options SOC_MV_DISCOVERY #makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options FFS # Berkeley Fast Filesystem options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=mge0 #options ROOTDEVNAME=\"ufs:/dev/da0a\" options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions options MUTEX_NOINLINE options RWLOCK_NOINLINE options NO_FFS_SNAPSHOT options NO_SWAPPING # Debugging options ALT_BREAK_TO_DEBUGGER options DDB #options DEADLKRES # Enable the deadlock resolver #options DIAGNOSTIC #options INVARIANTS # Enable calls of extra sanity checking #options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options KDB options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB device pci # Pseudo devices device loop device md device random # Serial ports device uart # Networking device ether device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy device bpf # USB options USB_DEBUG # enable debug msgs device usb device ehci device umass device scbus device pass device da # I2C (TWSI) device iic device iicbus device ds133x # SATA device mvs # NAND device nand +# GPIO +device gpio + # Flattened Device Tree options FDT options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=db78100.dts Index: projects/release-pkg/sys/arm/conf/DB-88F5XXX =================================================================== --- projects/release-pkg/sys/arm/conf/DB-88F5XXX (revision 294447) +++ projects/release-pkg/sys/arm/conf/DB-88F5XXX (revision 294448) @@ -1,93 +1,96 @@ # # Custom kernel for Marvell DB-88F5xxx boards. # # $FreeBSD$ # ident DB-88F5XXX include "std.arm" include "../mv/orion/std.db88f5xxx" options SOC_MV_ORION #makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options FFS # Berkeley Fast Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=mge0 #options ROOTDEVNAME=\"ufs:/dev/da0a\" options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions options MUTEX_NOINLINE options RWLOCK_NOINLINE options NO_FFS_SNAPSHOT options NO_SWAPPING # Debugging options ALT_BREAK_TO_DEBUGGER options DDB #options DEADLKRES # Enable the deadlock resolver #options DIAGNOSTIC #options INVARIANTS # Enable calls of extra sanity checking #options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options KDB options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB device pci # Pseudo devices device md device loop device random # Serial ports device uart # Networking device ether device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy device bpf options DEVICE_POLLING options HZ=1000 # I2C (TWSI) device iic device iicbus device ds133x # USB options USB_DEBUG # enable debug msgs device usb device ehci device umass device scbus device pass device da # SATA device mvs +# GPIO +device gpio + # Flattened Device Tree options FDT makeoptions FDT_DTS_FILE=db88f5281.dts Index: projects/release-pkg/sys/arm/conf/DB-88F6XXX =================================================================== --- projects/release-pkg/sys/arm/conf/DB-88F6XXX (revision 294447) +++ projects/release-pkg/sys/arm/conf/DB-88F6XXX (revision 294448) @@ -1,100 +1,103 @@ # # Custom kernel for Marvell DB-88F6xxx boards. # # $FreeBSD$ # ident DB-88F6XXX include "std.arm" include "../mv/kirkwood/std.db88f6xxx" options SOC_MV_KIRKWOOD makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options TMPFS # Efficient memory filesystem options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options MUTEX_NOINLINE options RWLOCK_NOINLINE options NO_FFS_SNAPSHOT options NO_SWAPPING # Debugging for use in -current #makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER options KDB # Enable kernel debugger support options DDB # Enable the kernel debugger #options DEADLKRES # Enable the deadlock resolver #options INVARIANTS # Enable calls of extra sanity checking #options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB #options DIAGNOSTIC # NFS root from boopt/dhcp options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=mge0 #options ROOTDEVNAME=\"ufs:/dev/da0a\" device pci # Pseudo devices device loop device md device random # Serial ports device uart # Networking device ether device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy device bpf device cesa # Marvell security engine device crypto device cryptodev # USB options USB_DEBUG # enable debug msgs device usb device ehci device umass device scbus device pass device da # I2C (TWSI) device iic device iicbus # SATA device mvs # NAND device nand +# GPIO +device gpio + # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=db88f6281.dts Index: projects/release-pkg/sys/arm/conf/DOCKSTAR =================================================================== --- projects/release-pkg/sys/arm/conf/DOCKSTAR (revision 294447) +++ projects/release-pkg/sys/arm/conf/DOCKSTAR (revision 294448) @@ -1,165 +1,168 @@ # # Custom kernel for Seagate DockStar (Marvell SheevaPlug based) devices. # # $FreeBSD$ # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ # #NO_UNIVERSE ident DOCKSTAR include "std.arm" include "../mv/kirkwood/std.db88f6xxx" options SOC_MV_KIRKWOOD options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager #options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 filesystem options NULLFS # NULL filesystem options TMPFS # Efficient memory filesystem options GEOM_PART_GPT # GUID Partition Tables options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options GEOM_LABEL # Provides labelization options GEOM_ELI # Disk encryption options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER options KDB # Enable kernel debugger support options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS #options WITNESS # Enable checks to detect deadlocks and cycles #options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB #options DIAGNOSTIC # Enable these options for nfs root configured via BOOTP. #options BOOTP #options BOOTP_NFSROOT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=mge0 # If not using BOOTP, use something like one of these... #options ROOTDEVNAME=\"ufs:/dev/da0a\" options ROOTDEVNAME=\"ufs:/dev/da0s1a\" #options ROOTDEVNAME=\"ufs:/dev/da0p10\" #options ROOTDEVNAME=\"nfs:192.168.0.254/dreamplug\" # Misc pseudo devices device bpf # Required for DHCP device firmware # firmware(9) required for USB wlan device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys device random # Entropy device device tun # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support device wlan # 802.11 WLAN support # cam support for umass and ahci device scbus device pass device da # Serial ports device uart # Networking device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy # USB options USB_HOST_ALIGN=32 # Align DMA to cacheline #options USB_DEBUG # Compile in USB debug support device usb # Basic usb support device ehci # USB host controller device umass # Mass storage device uhid # Human-interface devices device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs device zyd # ZyDAS zb1211/zb1211b wireless NICs device urtw # Realtek RTL8187B/L USB device upgt # Conexant/Intersil PrismGT SoftMAC USB device u3g # USB-based 3G modems (Option, Huawei, Sierra) # I2C (TWSI) device iic device iicbus # Sound device sound device snd_uaudio #crypto device cesa # Marvell security engine device crypto device cryptodev # IPSec device enc options IPSEC options IPSEC_NAT_T options TCP_SIGNATURE # include support for RFC 2385 # IPFW options IPFIREWALL options IPFIREWALL_DEFAULT_TO_ACCEPT options IPFIREWALL_VERBOSE options IPFIREWALL_VERBOSE_LIMIT=100 options IPFIREWALL_NAT options LIBALIAS options DUMMYNET options IPDIVERT #PF device pf device pflog device pfsync +# GPIO +device gpio + # ALTQ, required for PF options ALTQ # Basic ALTQ support options ALTQ_CBQ # Class Based Queueing options ALTQ_RED # Random Early Detection options ALTQ_RIO # RED In/Out options ALTQ_HFSC # Hierarchical Packet Scheduler options ALTQ_CDNR # Traffic conditioner options ALTQ_PRIQ # Priority Queueing options ALTQ_NOPCC # Required if the TSC is unusable #options ALTQ_DEBUG # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=dockstar.dts Index: projects/release-pkg/sys/arm/conf/DREAMPLUG-1001 =================================================================== --- projects/release-pkg/sys/arm/conf/DREAMPLUG-1001 (revision 294447) +++ projects/release-pkg/sys/arm/conf/DREAMPLUG-1001 (revision 294448) @@ -1,181 +1,184 @@ # Kernel config for GlobalScale Technologies DreamPlug version 1001. # # This is for units that are version 10, revision 01, with NOR SPI flash. # These units are identified with the number "1001" on the S/N label. # # For more information on this file, please read the handbook section on # Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ # #NO_UNIVERSE ident DREAMPLUG-1001 include "std.arm" include "../mv/kirkwood/std.db88f6xxx" options SOC_MV_KIRKWOOD options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager #options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 filesystem options NULLFS # NULL filesystem options TMPFS # Efficient memory filesystem options GEOM_PART_GPT # GUID Partition Tables options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options GEOM_LABEL # Provides labelization options GEOM_ELI # Disk encryption options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER options KDB # Enable kernel debugger support options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS #options WITNESS # Enable checks to detect deadlocks and cycles #options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB #options DIAGNOSTIC # Enable these options for nfs root configured via BOOTP. #options BOOTP #options BOOTP_NFSROOT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=mge0 # If not using BOOTP, use something like one of these... #options ROOTDEVNAME=\"ufs:/dev/da1a\" options ROOTDEVNAME=\"ufs:/dev/da1s1a\" #options ROOTDEVNAME=\"ufs:/dev/da1p10\" #options ROOTDEVNAME=\"nfs:192.168.0.254/dreamplug\" # Misc pseudo devices device bpf # Required for DHCP device firmware # firmware(9) required for USB wlan device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys device random # Entropy device device tun # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support device wlan # 802.11 WLAN support # cam support for umass and ahci device scbus device pass device da device cd # Serial ports device uart # Networking device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy # USB options USB_HOST_ALIGN=32 # Align DMA to cacheline #options USB_DEBUG # Compile in USB debug support device usb # Basic usb support device ehci # USB host controller device umass # Mass storage device uhid # Human-interface devices device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs device zyd # ZyDAS zb1211/zb1211b wireless NICs device urtw # Realtek RTL8187B/L USB device upgt # Conexant/Intersil PrismGT SoftMAC USB device u3g # USB-based 3G modems (Option, Huawei, Sierra) # I2C (TWSI) device iic device iicbus +# GPIO +device gpio + # SATA device mvs device ahci # Sound device sound device snd_uaudio #crypto device cesa # Marvell security engine device crypto device cryptodev # IPSec device enc options IPSEC options IPSEC_NAT_T options TCP_SIGNATURE # include support for RFC 2385 # IPFW options IPFIREWALL options IPFIREWALL_DEFAULT_TO_ACCEPT options IPFIREWALL_VERBOSE options IPFIREWALL_VERBOSE_LIMIT=100 options IPFIREWALL_NAT options LIBALIAS options DUMMYNET options IPDIVERT #PF device pf device pflog device pfsync # ALTQ, required for PF options ALTQ # Basic ALTQ support options ALTQ_CBQ # Class Based Queueing options ALTQ_RED # Random Early Detection options ALTQ_RIO # RED In/Out options ALTQ_HFSC # Hierarchical Packet Scheduler options ALTQ_CDNR # Traffic conditioner options ALTQ_PRIQ # Priority Queueing options ALTQ_NOPCC # Required if the TSC is unusable #options ALTQ_DEBUG # To use this configuration with the (rare) model 1001N (nand flash), # create a kernel config file that looks like this: # # include DREAMPLUG-1001 # nomakeoptions FDT_DTS_FILE # makeoptions FDT_DTS_FILE=dreamplug-1001N.dts # device nand # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=dreamplug-1001.dts Index: projects/release-pkg/sys/arm/conf/SHEEVAPLUG =================================================================== --- projects/release-pkg/sys/arm/conf/SHEEVAPLUG (revision 294447) +++ projects/release-pkg/sys/arm/conf/SHEEVAPLUG (revision 294448) @@ -1,88 +1,91 @@ # # Custom kernel for Marvell SheevaPlug devices. # # $FreeBSD$ # #NO_UNIVERSE ident SHEEVAPLUG include "std.arm" include "../mv/kirkwood/std.db88f6xxx" options SOC_MV_KIRKWOOD makeoptions WERROR="-Werror" options HZ=1000 options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options TMPFS # Efficient memory filesystem options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options MUTEX_NOINLINE options RWLOCK_NOINLINE options NO_FFS_SNAPSHOT options NO_SWAPPING # Debugging for use in -current #makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER options KDB # Enable kernel debugger support options DDB # Enable the kernel debugger # NFS root from boopt/dhcp options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=mge0 # Root fs on USB device #options ROOTDEVNAME=\"ufs:/dev/da0a\" # Pseudo devices device loop device random # Serial ports device uart # Networking device ether device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy device bpf options DEVICE_POLLING device vlan device cesa # Marvell security engine device crypto device cryptodev # USB options USB_DEBUG # enable debug msgs device usb device ehci device umass device scbus device pass device da # NAND device nand +# GPIO +device gpio + # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=sheevaplug.dts Index: projects/release-pkg/sys/arm/conf/TS7800 =================================================================== --- projects/release-pkg/sys/arm/conf/TS7800 (revision 294447) +++ projects/release-pkg/sys/arm/conf/TS7800 (revision 294448) @@ -1,83 +1,86 @@ # # Custom kernel for the TS-7800 board. # # $FreeBSD$ # ident TS7800 include "std.arm" include "../mv/orion/std.ts7800" options SOC_MV_ORION #makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=mge0 options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions options MUTEX_NOINLINE options RWLOCK_NOINLINE options NO_FFS_SNAPSHOT options NO_SWAPPING # Debugging options ALT_BREAK_TO_DEBUGGER options DDB options KDB options GDB # Support remote GDB. device mvs device pci # Pseudo devices device md device loop device random # Serial ports device uart # Networking device ether device mge # Marvell Gigabit Ethernet controller device mii device mdio device e1000phy device bpf options HZ=1000 # USB device usb device ehci device umass device scbus device pass device da # SATA device ata +# GPIO +device gpio + # Flattened Device Tree options FDT options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=ts7800.dts Index: projects/release-pkg/sys/arm/mv/armada38x/armada38x_mp.c =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/armada38x_mp.c (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/armada38x_mp.c (revision 294448) @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 2015 Semihalf. + * Copyright (c) 2015 Stormshield. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "pmsu.h" + +int cpu_reset_deassert(void); + +int +cpu_reset_deassert(void) +{ + bus_space_handle_t vaddr; + uint32_t reg; + int rv; + + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_CPU_RESET_BASE, + MV_CPU_RESET_REGS_LEN, 0, &vaddr); + if (rv != 0) + return (rv); + + /* CPU1 is held at reset by default - clear assert bit to release it */ + reg = bus_space_read_4(fdtbus_bs_tag, vaddr, CPU_RESET_OFFSET(1)); + reg &= ~CPU_RESET_ASSERT; + + bus_space_write_4(fdtbus_bs_tag, vaddr, CPU_RESET_OFFSET(1), reg); + + bus_space_unmap(fdtbus_bs_tag, vaddr, MV_CPU_RESET_REGS_LEN); + + return (0); +} + +static int +platform_cnt_cpus(void) +{ + bus_space_handle_t vaddr_scu; + phandle_t cpus_node, child; + char device_type[16]; + int fdt_cpu_count = 0; + int reg_cpu_count = 0; + uint32_t val; + int rv; + + cpus_node = OF_finddevice("/cpus"); + if (cpus_node == -1) { + /* Default is one core */ + mp_ncpus = 1; + return (0); + } + + /* Get number of 'cpu' nodes from FDT */ + for (child = OF_child(cpus_node); child != 0; child = OF_peer(child)) { + /* Check if child is a CPU */ + memset(device_type, 0, sizeof(device_type)); + rv = OF_getprop(child, "device_type", device_type, + sizeof(device_type) - 1); + if (rv < 0) + continue; + if (strcmp(device_type, "cpu") != 0) + continue; + + fdt_cpu_count++; + } + + /* Get number of CPU cores from SCU register to cross-check with FDT */ + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_SCU_BASE, + MV_SCU_REGS_LEN, 0, &vaddr_scu); + if (rv != 0) { + /* Default is one core */ + mp_ncpus = 1; + return (0); + } + + val = bus_space_read_4(fdtbus_bs_tag, vaddr_scu, MV_SCU_REG_CONFIG); + bus_space_unmap(fdtbus_bs_tag, vaddr_scu, MV_SCU_REGS_LEN); + reg_cpu_count = (val & SCU_CFG_REG_NCPU_MASK) + 1; + + /* Set mp_ncpus to number of cpus in FDT unless SOC contains only one */ + mp_ncpus = min(reg_cpu_count, fdt_cpu_count); + /* mp_ncpus must be at least 1 */ + mp_ncpus = max(1, mp_ncpus); + + return (mp_ncpus); +} + +void +platform_mp_setmaxid(void) +{ + + /* Armada38x family supports maximum 2 cores */ + mp_ncpus = platform_cnt_cpus(); + mp_maxid = 1; +} + +int +platform_mp_probe(void) +{ + + return (mp_ncpus > 1); +} + +void +platform_mp_init_secondary(void) +{ + + intr_pic_init_secondary(); +} + +void +platform_mp_start_ap(void) +{ + int rv; + + /* Write secondary entry address to PMSU register */ + rv = pmsu_boot_secondary_cpu(); + if (rv != 0) + return; + + /* Release CPU1 from reset */ + cpu_reset_deassert(); +} + +void +platform_ipi_send(cpuset_t cpus, u_int ipi) +{ + + pic_ipi_send(cpus, ipi); +} Property changes on: projects/release-pkg/sys/arm/mv/armada38x/armada38x_mp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/files.armada38x =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/files.armada38x (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/files.armada38x (revision 294448) @@ -0,0 +1,6 @@ +# $FreeBSD$ + +arm/mv/armada38x/armada38x.c standard +arm/mv/armada38x/armada38x_mp.c optional smp +arm/mv/armada38x/pmsu.c standard +arm/mv/armada38x/rtc.c standard Property changes on: projects/release-pkg/sys/arm/mv/armada38x/files.armada38x ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/pmsu.c =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/pmsu.c (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/pmsu.c (revision 294448) @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 2015 Semihalf. + * Copyright (c) 2015 Stormshield. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include "pmsu.h" + +static struct resource_spec pmsu_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct pmsu_softc { + device_t dev; + struct resource *res; +}; + +static int pmsu_probe(device_t dev); +static int pmsu_attach(device_t dev); +static int pmsu_detach(device_t dev); + +static device_method_t pmsu_methods[] = { + DEVMETHOD(device_probe, pmsu_probe), + DEVMETHOD(device_attach, pmsu_attach), + DEVMETHOD(device_detach, pmsu_detach), + + { 0, 0 } +}; + +static driver_t pmsu_driver = { + "pmsu", + pmsu_methods, + sizeof(struct pmsu_softc) +}; + +static devclass_t pmsu_devclass; + +DRIVER_MODULE(pmsu, simplebus, pmsu_driver, pmsu_devclass, 0, 0); +DRIVER_MODULE(pmsu, ofwbus, pmsu_driver, pmsu_devclass, 0, 0); + +static int +pmsu_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "marvell,armada-380-pmsu")) + return (ENXIO); + + device_set_desc(dev, "Power Management Service Unit"); + + return (BUS_PROBE_DEFAULT); +} + +static int +pmsu_attach(device_t dev) +{ + struct pmsu_softc *sc; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + err = bus_alloc_resources(dev, pmsu_spec, &sc->res); + if (err != 0) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + return (0); +} + +static int +pmsu_detach(device_t dev) +{ + struct pmsu_softc *sc; + + sc = device_get_softc(dev); + + bus_release_resources(dev, pmsu_spec, &sc->res); + + return (0); +} + +#ifdef SMP +int +pmsu_boot_secondary_cpu(void) +{ + bus_space_handle_t vaddr; + int rv; + + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_PMSU_BASE, MV_PMSU_REGS_LEN, + 0, &vaddr); + if (rv != 0) + return (rv); + + /* Boot cpu1 */ + bus_space_write_4(fdtbus_bs_tag, vaddr, PMSU_BOOT_ADDR_REDIRECT_OFFSET(1), + pmap_kextract((vm_offset_t)mpentry)); + + cpu_idcache_wbinv_all(); + cpu_l2cache_wbinv_all(); + armv7_sev(); + + bus_space_unmap(fdtbus_bs_tag, vaddr, MV_PMSU_REGS_LEN); + + return (0); +} +#endif Property changes on: projects/release-pkg/sys/arm/mv/armada38x/pmsu.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/pmsu.h =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/pmsu.h (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/pmsu.h (revision 294448) @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2015 Semihalf. + * Copyright (c) 2015 Stormshield. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_global.h" + +#ifdef SMP +/* Boot secondary core using PMSU */ +int pmsu_boot_secondary_cpu(void); +#endif Property changes on: projects/release-pkg/sys/arm/mv/armada38x/pmsu.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/std.armada38x =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/std.armada38x (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/std.armada38x (revision 294448) @@ -0,0 +1,12 @@ +# $FreeBSD$ +files "../mv/armada38x/files.armada38x" +files "../mv/files.mv" +cpu CPU_CORTEXA +machine arm armv6 + +makeoptions CONF_CFLAGS="-march=armv7a" +makeoptions KERNVIRTADDR=0xc0000000 + +options KERNVIRTADDR=0xc0000000 +options IPI_IRQ_START=0 +options IPI_IRQ_END=15 Property changes on: projects/release-pkg/sys/arm/mv/armada38x/std.armada38x ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/armada38x.c =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/armada38x.c (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/armada38x.c (revision 294448) @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2015 Semihalf. + * Copyright (c) 2015 Stormshield. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include +#include +#include + +int armada38x_open_bootrom_win(void); +int armada38x_scu_enable(void); +int armada38x_win_set_iosync_barrier(void); + +uint32_t +get_tclk(void) +{ + uint32_t sar; + + /* + * On Armada38x TCLK can be configured to 250 MHz or 200 MHz. + * Current setting is read from Sample At Reset register. + */ + sar = (uint32_t)get_sar_value(); + sar = (sar & TCLK_MASK) >> TCLK_SHIFT; + if (sar == 0) + return (TCLK_250MHZ); + else + return (TCLK_200MHZ); +} + +int +armada38x_win_set_iosync_barrier(void) +{ + bus_space_handle_t vaddr_iowind; + int rv; + + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_MBUS_BRIDGE_BASE, + MV_CPU_SUBSYS_REGS_LEN, 0, &vaddr_iowind); + if (rv != 0) + return (rv); + + /* Set Sync Barrier flags for all Mbus internal units */ + bus_space_write_4(fdtbus_bs_tag, vaddr_iowind, MV_SYNC_BARRIER_CTRL, + MV_SYNC_BARRIER_CTRL_ALL); + + bus_space_barrier(fdtbus_bs_tag, vaddr_iowind, 0, + MV_CPU_SUBSYS_REGS_LEN, BUS_SPACE_BARRIER_WRITE); + bus_space_unmap(fdtbus_bs_tag, vaddr_iowind, MV_CPU_SUBSYS_REGS_LEN); + + return (rv); +} + +int +armada38x_open_bootrom_win(void) +{ + bus_space_handle_t vaddr_iowind; + uint32_t val; + int rv; + + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_MBUS_BRIDGE_BASE, + MV_CPU_SUBSYS_REGS_LEN, 0, &vaddr_iowind); + if (rv != 0) + return (rv); + + val = (MV_BOOTROM_WIN_SIZE & IO_WIN_SIZE_MASK) << IO_WIN_SIZE_SHIFT; + val |= (MBUS_BOOTROM_ATTR & IO_WIN_ATTR_MASK) << IO_WIN_ATTR_SHIFT; + val |= (MBUS_BOOTROM_TGT_ID & IO_WIN_TGT_MASK) << IO_WIN_TGT_SHIFT; + /* Enable window and Sync Barrier */ + val |= (0x1 & IO_WIN_SYNC_MASK) << IO_WIN_SYNC_SHIFT; + val |= (0x1 & IO_WIN_ENA_MASK) << IO_WIN_ENA_SHIFT; + + /* Configure IO Window Control Register */ + bus_space_write_4(fdtbus_bs_tag, vaddr_iowind, IO_WIN_9_CTRL_OFFSET, + val); + /* Configure IO Window Base Register */ + bus_space_write_4(fdtbus_bs_tag, vaddr_iowind, IO_WIN_9_BASE_OFFSET, + MV_BOOTROM_MEM_ADDR); + + bus_space_barrier(fdtbus_bs_tag, vaddr_iowind, 0, MV_CPU_SUBSYS_REGS_LEN, + BUS_SPACE_BARRIER_WRITE); + bus_space_unmap(fdtbus_bs_tag, vaddr_iowind, MV_CPU_SUBSYS_REGS_LEN); + + return (rv); +} + +int +armada38x_scu_enable(void) +{ + bus_space_handle_t vaddr_scu; + int rv; + uint32_t val; + + rv = bus_space_map(fdtbus_bs_tag, (bus_addr_t)MV_SCU_BASE, + MV_SCU_REGS_LEN, 0, &vaddr_scu); + if (rv != 0) + return (rv); + + /* Enable SCU */ + val = bus_space_read_4(fdtbus_bs_tag, vaddr_scu, MV_SCU_REG_CTRL); + if (!(val & MV_SCU_ENABLE)) + bus_space_write_4(fdtbus_bs_tag, vaddr_scu, 0, + val | MV_SCU_ENABLE); + + bus_space_unmap(fdtbus_bs_tag, vaddr_scu, MV_SCU_REGS_LEN); + return (0); +} Property changes on: projects/release-pkg/sys/arm/mv/armada38x/armada38x.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armada38x/rtc.c =================================================================== --- projects/release-pkg/sys/arm/mv/armada38x/rtc.c (nonexistent) +++ projects/release-pkg/sys/arm/mv/armada38x/rtc.c (revision 294448) @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2015 Semihalf. + * Copyright (c) 2015 Stormshield. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "clock_if.h" + +#define RTC_RES_US 1000000 +#define HALF_OF_SEC_NS 500000000 + +#define RTC_STATUS 0x0 +#define RTC_TIME 0xC + +#define MV_RTC_LOCK(sc) mtx_lock(&(sc)->mutex) +#define MV_RTC_UNLOCK(sc) mtx_unlock(&(sc)->mutex) + +static struct resource_spec res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct mv_rtc_softc { + device_t dev; + struct resource *res; + struct mtx mutex; +}; + +static int mv_rtc_probe(device_t dev); +static int mv_rtc_attach(device_t dev); +static int mv_rtc_detach(device_t dev); + +static int mv_rtc_gettime(device_t dev, struct timespec *ts); +static int mv_rtc_settime(device_t dev, struct timespec *ts); + +static uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off); +static int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, + uint32_t val); + +static device_method_t mv_rtc_methods[] = { + DEVMETHOD(device_probe, mv_rtc_probe), + DEVMETHOD(device_attach, mv_rtc_attach), + DEVMETHOD(device_detach, mv_rtc_detach), + + DEVMETHOD(clock_gettime, mv_rtc_gettime), + DEVMETHOD(clock_settime, mv_rtc_settime), + + { 0, 0 }, +}; + +static driver_t mv_rtc_driver = { + "rtc", + mv_rtc_methods, + sizeof(struct mv_rtc_softc), +}; + +static devclass_t mv_rtc_devclass; + +DRIVER_MODULE(mv_rtc, simplebus, mv_rtc_driver, mv_rtc_devclass, 0, 0); + +static int +mv_rtc_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "marvell,armada-380-rtc")) + return (ENXIO); + + device_set_desc(dev, "Marvell Integrated RTC"); + + return (BUS_PROBE_DEFAULT); +} + +static int +mv_rtc_attach(device_t dev) +{ + struct mv_rtc_softc *sc; + int unit, ret; + + unit = device_get_unit(dev); + + sc = device_get_softc(dev); + sc->dev = dev; + + clock_register(dev, RTC_RES_US); + + mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_DEF); + + ret = bus_alloc_resources(dev, res_spec, &sc->res); + if (ret != 0) { + device_printf(dev, "could not allocate resources\n"); + mtx_destroy(&sc->mutex); + return (ENXIO); + } + + return (0); +} + +static int +mv_rtc_detach(device_t dev) +{ + struct mv_rtc_softc *sc; + + sc = device_get_softc(dev); + + mtx_destroy(&sc->mutex); + + bus_release_resources(dev, res_spec, &sc->res); + + return (0); +} + +static int +mv_rtc_gettime(device_t dev, struct timespec *ts) +{ + struct mv_rtc_softc *sc; + uint32_t val, val_check; + + sc = device_get_softc(dev); + + MV_RTC_LOCK(sc); + /* + * According to HW Errata if more than one second between + * two time reads is detected, then read once again + */ + val = mv_rtc_reg_read(sc, RTC_TIME); + val_check = mv_rtc_reg_read(sc, RTC_TIME); + if (val_check - val > 1) + val_check = mv_rtc_reg_read(sc, RTC_TIME); + + MV_RTC_UNLOCK(sc); + + ts->tv_sec = val_check; + /* RTC resolution is 1 sec */ + ts->tv_nsec = 0; + + return (0); +} + +static int +mv_rtc_settime(device_t dev, struct timespec *ts) +{ + struct mv_rtc_softc *sc; + + sc = device_get_softc(dev); + + /* RTC resolution is 1 sec */ + if (ts->tv_nsec >= HALF_OF_SEC_NS) + ts->tv_sec++; + ts->tv_nsec = 0; + + MV_RTC_LOCK(sc); + + /* + * According to errata FE-3124064, Write to RTC TIME register + * may fail. As a workaround, before writing to RTC TIME register, + * issue a dummy write of 0x0 twice to RTC Status register. + */ + mv_rtc_reg_write(sc, RTC_STATUS, 0x0); + mv_rtc_reg_write(sc, RTC_STATUS, 0x0); + mv_rtc_reg_write(sc, RTC_TIME, ts->tv_sec); + + MV_RTC_UNLOCK(sc); + + return (0); +} + +static uint32_t +mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->res, off)); +} + +/* + * According to the datasheet, the OS should wait 5us after every + * register write to the RTC hard macro so that the required update + * can occur without holding off the system bus + */ +static int +mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->res, off, val); + DELAY(5); + + return (0); +} Property changes on: projects/release-pkg/sys/arm/mv/armada38x/rtc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/arm/mv/armadaxp/armadaxp.c =================================================================== --- projects/release-pkg/sys/arm/mv/armadaxp/armadaxp.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/armadaxp/armadaxp.c (revision 294448) @@ -1,307 +1,300 @@ /*- * Copyright (c) 2011 Semihalf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: FreeBSD: src/sys/arm/mv/kirkwood/sheevaplug.c,v 1.2 2010/06/13 13:28:53 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define CPU_FREQ_FIELD(sar) (((0x01 & (sar >> 52)) << 3) | \ (0x07 & (sar >> 21))) #define FAB_FREQ_FIELD(sar) (((0x01 & (sar >> 51)) << 4) | \ (0x0F & (sar >> 24))) static uint32_t count_l2clk(void); void armadaxp_l2_init(void); void armadaxp_init_coher_fabric(void); int platform_get_ncpus(void); #define ARMADAXP_L2_BASE (MV_BASE + 0x8000) #define ARMADAXP_L2_CTRL 0x100 #define L2_ENABLE (1 << 0) #define ARMADAXP_L2_AUX_CTRL 0x104 #define L2_WBWT_MODE_MASK (3 << 0) #define L2_WBWT_MODE_PAGE 0 #define L2_WBWT_MODE_WB 1 #define L2_WBWT_MODE_WT 2 #define L2_REP_STRAT_MASK (3 << 27) #define L2_REP_STRAT_LSFR (1 << 27) #define L2_REP_STRAT_SEMIPLRU (3 << 27) #define ARMADAXP_L2_CNTR_CTRL 0x200 #define ARMADAXP_L2_CNTR_CONF(x) (0x204 + (x) * 0xc) #define ARMADAXP_L2_CNTR2_VAL_LOW (0x208 + (x) * 0xc) #define ARMADAXP_L2_CNTR2_VAL_HI (0x20c + (x) * 0xc) #define ARMADAXP_L2_INT_CAUSE 0x220 #define ARMADAXP_L2_SYNC_BARRIER 0x700 #define ARMADAXP_L2_INV_WAY 0x778 #define ARMADAXP_L2_CLEAN_WAY 0x7BC #define ARMADAXP_L2_FLUSH_PHYS 0x7F0 #define ARMADAXP_L2_FLUSH_WAY 0x7FC #define MV_COHERENCY_FABRIC_BASE (MV_MBUS_BRIDGE_BASE + 0x200) #define COHER_FABRIC_CTRL 0x00 #define COHER_FABRIC_CONF 0x04 #define COHER_FABRIC_CFU 0x28 #define COHER_FABRIC_CIB_CTRL 0x80 -/* XXX Make gpio driver optional and remove it */ -struct resource_spec mv_gpio_res[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { -1, 0 } -}; - struct vco_freq_ratio { uint8_t vco_cpu; /* VCO to CLK0(CPU) clock ratio */ uint8_t vco_l2c; /* VCO to NB(L2 cache) clock ratio */ uint8_t vco_hcl; /* VCO to HCLK(DDR controller) clock ratio */ uint8_t vco_ddr; /* VCO to DR(DDR memory) clock ratio */ }; static struct vco_freq_ratio freq_conf_table[] = { /*00*/ { 1, 1, 4, 2 }, /*01*/ { 1, 2, 2, 2 }, /*02*/ { 2, 2, 6, 3 }, /*03*/ { 2, 2, 3, 3 }, /*04*/ { 1, 2, 3, 3 }, /*05*/ { 1, 2, 4, 2 }, /*06*/ { 1, 1, 2, 2 }, /*07*/ { 2, 3, 6, 6 }, /*08*/ { 2, 3, 5, 5 }, /*09*/ { 1, 2, 6, 3 }, /*10*/ { 2, 4, 10, 5 }, /*11*/ { 1, 3, 6, 6 }, /*12*/ { 1, 2, 5, 5 }, /*13*/ { 1, 3, 6, 3 }, /*14*/ { 1, 2, 5, 5 }, /*15*/ { 2, 2, 5, 5 }, /*16*/ { 1, 1, 3, 3 }, /*17*/ { 2, 5, 10, 10 }, /*18*/ { 1, 3, 8, 4 }, /*19*/ { 1, 1, 2, 1 }, /*20*/ { 2, 3, 6, 3 }, /*21*/ { 1, 2, 8, 4 }, /*22*/ { 2, 5, 10, 5 } }; static uint16_t cpu_clock_table[] = { 1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600, 667, 800, 1600, 2133, 2200, 2400 }; uint32_t get_tclk(void) { uint32_t cputype; cputype = cpufunc_id(); cputype &= CPU_ID_CPU_MASK; if (cputype == CPU_ID_MV88SV584X_V7) return (TCLK_250MHZ); else return (TCLK_200MHZ); } static uint32_t count_l2clk(void) { uint64_t sar_reg; uint32_t freq_vco, freq_l2clk; uint8_t sar_cpu_freq, sar_fab_freq, array_size; /* Get value of the SAR register and process it */ sar_reg = get_sar_value(); sar_cpu_freq = CPU_FREQ_FIELD(sar_reg); sar_fab_freq = FAB_FREQ_FIELD(sar_reg); /* Check if CPU frequency field has correct value */ array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]); if (sar_cpu_freq >= array_size) panic("Reserved value in cpu frequency configuration field: " "%d", sar_cpu_freq); /* Check if fabric frequency field has correct value */ array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]); if (sar_fab_freq >= array_size) panic("Reserved value in fabric frequency configuration field: " "%d", sar_fab_freq); /* Get CPU clock frequency */ freq_vco = cpu_clock_table[sar_cpu_freq] * freq_conf_table[sar_fab_freq].vco_cpu; /* Get L2CLK clock frequency */ freq_l2clk = freq_vco / freq_conf_table[sar_fab_freq].vco_l2c; /* Round L2CLK value to integer MHz */ if (((freq_vco % freq_conf_table[sar_fab_freq].vco_l2c) * 10 / freq_conf_table[sar_fab_freq].vco_l2c) >= 5) freq_l2clk++; return (freq_l2clk * 1000000); } uint32_t get_l2clk(void) { static uint32_t l2clk_freq = 0; /* If get_l2clk is called first time get L2CLK value from register */ if (l2clk_freq == 0) l2clk_freq = count_l2clk(); return (l2clk_freq); } static uint32_t read_coher_fabric(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg)); } static void write_coher_fabric(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg, val); } int platform_get_ncpus(void) { #if !defined(SMP) return (1); #else return ((read_coher_fabric(COHER_FABRIC_CONF) & 0xf) + 1); #endif } void armadaxp_init_coher_fabric(void) { uint32_t val, cpus, mask; cpus = platform_get_ncpus(); mask = (1 << cpus) - 1; val = read_coher_fabric(COHER_FABRIC_CTRL); val |= (mask << 24); write_coher_fabric(COHER_FABRIC_CTRL, val); val = read_coher_fabric(COHER_FABRIC_CONF); val |= (mask << 24); val |= (1 << 15); write_coher_fabric(COHER_FABRIC_CONF, val); } #define ALL_WAYS 0xffffffff /* L2 cache configuration registers */ static uint32_t read_l2_cache(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, ARMADAXP_L2_BASE, reg)); } static void write_l2_cache(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, ARMADAXP_L2_BASE, reg, val); } static void armadaxp_l2_idcache_inv_all(void) { write_l2_cache(ARMADAXP_L2_INV_WAY, ALL_WAYS); } void armadaxp_l2_init(void) { u_int32_t reg; /* Set L2 policy */ reg = read_l2_cache(ARMADAXP_L2_AUX_CTRL); reg &= ~(L2_WBWT_MODE_MASK); reg &= ~(L2_REP_STRAT_MASK); reg |= L2_REP_STRAT_SEMIPLRU; reg |= L2_WBWT_MODE_WT; write_l2_cache(ARMADAXP_L2_AUX_CTRL, reg); /* Invalidate l2 cache */ armadaxp_l2_idcache_inv_all(); /* Clear pending L2 interrupts */ write_l2_cache(ARMADAXP_L2_INT_CAUSE, 0x1ff); /* Enable l2 cache */ reg = read_l2_cache(ARMADAXP_L2_CTRL); write_l2_cache(ARMADAXP_L2_CTRL, reg | L2_ENABLE); /* * For debug purposes * Configure and enable counter */ write_l2_cache(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2)); write_l2_cache(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2)); write_l2_cache(ARMADAXP_L2_CNTR_CTRL, 0x303); /* * Enable Cache maintenance operation propagation in coherency fabric * Change point of coherency and point of unification to DRAM. */ reg = read_coher_fabric(COHER_FABRIC_CFU); reg |= (1 << 17) | (1 << 18); write_coher_fabric(COHER_FABRIC_CFU, reg); /* Coherent IO Bridge initialization */ reg = read_coher_fabric(COHER_FABRIC_CIB_CTRL); reg &= ~(7 << 16); reg |= (7 << 16); write_coher_fabric(COHER_FABRIC_CIB_CTRL, reg); } Index: projects/release-pkg/sys/arm/mv/files.mv =================================================================== --- projects/release-pkg/sys/arm/mv/files.mv (revision 294447) +++ projects/release-pkg/sys/arm/mv/files.mv (revision 294448) @@ -1,31 +1,31 @@ # $FreeBSD$ # # The Marvell CPU cores # - Compliant with V5TE architecture # - Super scalar dual issue CPU # - Big/Little Endian # - MMU/MPU # - L1 Cache: Supports streaming and write allocate # - Variable pipeline stages # - Out-of-order execution # - Branch Prediction # - JTAG/ICE # - Vector Floating Point (VFP) unit # -arm/mv/gpio.c standard +arm/mv/gpio.c optional gpio arm/mv/mv_common.c standard arm/mv/mv_localbus.c standard arm/mv/mv_machdep.c standard arm/mv/mv_pci.c optional pci arm/mv/mv_ts.c standard arm/mv/timer.c standard arm/mv/twsi.c optional iicbus dev/cesa/cesa.c optional cesa dev/mge/if_mge.c optional mge dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/usb/controller/ehci_mv.c optional ehci kern/kern_clocksource.c standard Index: projects/release-pkg/sys/arm/mv/mv_common.c =================================================================== --- projects/release-pkg/sys/arm/mv/mv_common.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/mv_common.c (revision 294448) @@ -1,2207 +1,2231 @@ /*- * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include MALLOC_DEFINE(M_IDMA, "idma", "idma dma test memory"); #define IDMA_DEBUG #undef IDMA_DEBUG #define MAX_CPU_WIN 5 #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif #ifdef DEBUG #define MV_DUMP_WIN 1 #else #define MV_DUMP_WIN 0 #endif static int win_eth_can_remap(int i); #ifndef SOC_MV_FREY static int decode_win_cpu_valid(void); #endif static int decode_win_usb_valid(void); static int decode_win_eth_valid(void); static int decode_win_pcie_valid(void); static int decode_win_sata_valid(void); static int decode_win_idma_valid(void); static int decode_win_xor_valid(void); #ifndef SOC_MV_FREY static void decode_win_cpu_setup(void); #endif #ifdef SOC_MV_ARMADAXP static int decode_win_sdram_fixup(void); #endif static void decode_win_usb_setup(u_long); static void decode_win_eth_setup(u_long); static void decode_win_sata_setup(u_long); static void decode_win_idma_setup(u_long); static void decode_win_xor_setup(u_long); static void decode_win_usb_dump(u_long); static void decode_win_eth_dump(u_long base); static void decode_win_idma_dump(u_long base); static void decode_win_xor_dump(u_long base); static int fdt_get_ranges(const char *, void *, int, int *, int *); +#ifdef SOC_MV_ARMADA38X +int gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, + int *trig, int *pol); +#endif static int win_cpu_from_dt(void); static int fdt_win_setup(void); static uint32_t dev_mask = 0; static int cpu_wins_no = 0; static int eth_port = 0; static int usb_port = 0; static struct decode_win cpu_win_tbl[MAX_CPU_WIN]; const struct decode_win *cpu_wins = cpu_win_tbl; typedef void (*decode_win_setup_t)(u_long); typedef void (*dump_win_t)(u_long); struct soc_node_spec { const char *compat; decode_win_setup_t decode_handler; dump_win_t dump_handler; }; static struct soc_node_spec soc_nodes[] = { { "mrvl,ge", &decode_win_eth_setup, &decode_win_eth_dump }, { "mrvl,usb-ehci", &decode_win_usb_setup, &decode_win_usb_dump }, { "mrvl,sata", &decode_win_sata_setup, NULL }, { "mrvl,xor", &decode_win_xor_setup, &decode_win_xor_dump }, { "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump }, { "mrvl,pcie", &decode_win_pcie_setup, NULL }, { NULL, NULL, NULL }, }; struct fdt_pm_mask_entry fdt_pm_mask_table[] = { { "mrvl,ge", CPU_PM_CTRL_GE(0) }, { "mrvl,ge", CPU_PM_CTRL_GE(1) }, { "mrvl,usb-ehci", CPU_PM_CTRL_USB(0) }, { "mrvl,usb-ehci", CPU_PM_CTRL_USB(1) }, { "mrvl,usb-ehci", CPU_PM_CTRL_USB(2) }, { "mrvl,xor", CPU_PM_CTRL_XOR }, { "mrvl,sata", CPU_PM_CTRL_SATA }, { NULL, 0 } }; static __inline int pm_is_disabled(uint32_t mask) { #if defined(SOC_MV_KIRKWOOD) return (soc_power_ctrl_get(mask) == mask); #else return (soc_power_ctrl_get(mask) == mask ? 0 : 1); #endif } /* * Disable device using power management register. * 1 - Device Power On * 0 - Device Power Off * Mask can be set in loader. * EXAMPLE: * loader> set hw.pm-disable-mask=0x2 * * Common mask: * |-------------------------------| * | Device | Kirkwood | Discovery | * |-------------------------------| * | USB0 | 0x00008 | 0x020000 | * |-------------------------------| * | USB1 | - | 0x040000 | * |-------------------------------| * | USB2 | - | 0x080000 | * |-------------------------------| * | GE0 | 0x00001 | 0x000002 | * |-------------------------------| * | GE1 | - | 0x000004 | * |-------------------------------| * | IDMA | - | 0x100000 | * |-------------------------------| * | XOR | 0x10000 | 0x200000 | * |-------------------------------| * | CESA | 0x20000 | 0x400000 | * |-------------------------------| * | SATA | 0x04000 | 0x004000 | * --------------------------------| * This feature can be used only on Kirkwood and Discovery * machines. */ static __inline void pm_disable_device(int mask) { #ifdef DIAGNOSTIC uint32_t reg; reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); printf("Power Management Register: 0%x\n", reg); reg &= ~mask; soc_power_ctrl_set(reg); printf("Device %x is disabled\n", mask); reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); printf("Power Management Register: 0%x\n", reg); #endif } int fdt_pm(phandle_t node) { uint32_t cpu_pm_ctrl; int i, ena, compat; ena = 1; cpu_pm_ctrl = read_cpu_ctrl(CPU_PM_CTRL); for (i = 0; fdt_pm_mask_table[i].compat != NULL; i++) { if (dev_mask & (1 << i)) continue; compat = fdt_is_compatible(node, fdt_pm_mask_table[i].compat); #if defined(SOC_MV_KIRKWOOD) if (compat && (cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { dev_mask |= (1 << i); ena = 0; break; } else if (compat) { dev_mask |= (1 << i); break; } #else if (compat && (~cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { dev_mask |= (1 << i); ena = 0; break; } else if (compat) { dev_mask |= (1 << i); break; } #endif } return (ena); } uint32_t read_cpu_ctrl(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg)); } void write_cpu_ctrl(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg, val); } -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) uint32_t read_cpu_mp_clocks(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg)); } void write_cpu_mp_clocks(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg, val); } uint32_t read_cpu_misc(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, reg)); } void write_cpu_misc(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, MV_MISC_BASE, reg, val); } #endif void cpu_reset(void) { -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined (SOC_MV_ARMADA38X) write_cpu_misc(RSTOUTn_MASK, SOFT_RST_OUT_EN); write_cpu_misc(SYSTEM_SOFT_RESET, SYS_SOFT_RST); #else write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN); write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST); #endif while (1); } uint32_t cpu_extra_feat(void) { uint32_t dev, rev; uint32_t ef = 0; soc_id(&dev, &rev); switch (dev) { case MV_DEV_88F6281: case MV_DEV_88F6282: case MV_DEV_88RC8180: case MV_DEV_MV78100_Z0: case MV_DEV_MV78100: __asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef)); break; case MV_DEV_88F5182: case MV_DEV_88F5281: __asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef)); break; default: if (bootverbose) printf("This ARM Core does not support any extra features\n"); } return (ef); } /* * Get the power status of device. This feature is only supported on * Kirkwood and Discovery SoCs. */ uint32_t soc_power_ctrl_get(uint32_t mask) { #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) && !defined(SOC_MV_FREY) if (mask != CPU_PM_CTRL_NONE) mask &= read_cpu_ctrl(CPU_PM_CTRL); return (mask); #else return (mask); #endif } /* * Set the power status of device. This feature is only supported on * Kirkwood and Discovery SoCs. */ void soc_power_ctrl_set(uint32_t mask) { #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) if (mask != CPU_PM_CTRL_NONE) write_cpu_ctrl(CPU_PM_CTRL, mask); #endif } void soc_id(uint32_t *dev, uint32_t *rev) { /* * Notice: system identifiers are available in the registers range of * PCIE controller, so using this function is only allowed (and * possible) after the internal registers range has been mapped in via * pmap_devmap_bootstrap(). */ *dev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 0) >> 16; *rev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 8) & 0xff; } static void soc_identify(void) { uint32_t d, r, size, mode; const char *dev; const char *rev; soc_id(&d, &r); printf("SOC: "); if (bootverbose) printf("(0x%4x:0x%02x) ", d, r); rev = ""; switch (d) { case MV_DEV_88F5181: dev = "Marvell 88F5181"; if (r == 3) rev = "B1"; break; case MV_DEV_88F5182: dev = "Marvell 88F5182"; if (r == 2) rev = "A2"; break; case MV_DEV_88F5281: dev = "Marvell 88F5281"; if (r == 4) rev = "D0"; else if (r == 5) rev = "D1"; else if (r == 6) rev = "D2"; break; case MV_DEV_88F6281: dev = "Marvell 88F6281"; if (r == 0) rev = "Z0"; else if (r == 2) rev = "A0"; else if (r == 3) rev = "A1"; break; case MV_DEV_88RC8180: dev = "Marvell 88RC8180"; break; case MV_DEV_88RC9480: dev = "Marvell 88RC9480"; break; case MV_DEV_88RC9580: dev = "Marvell 88RC9580"; break; case MV_DEV_88F6781: dev = "Marvell 88F6781"; if (r == 2) rev = "Y0"; break; case MV_DEV_88F6282: dev = "Marvell 88F6282"; if (r == 0) rev = "A0"; else if (r == 1) rev = "A1"; break; + case MV_DEV_88F6828: + dev = "Marvell 88F6828"; + break; + case MV_DEV_88F6820: + dev = "Marvell 88F6820"; + break; + case MV_DEV_88F6810: + dev = "Marvell 88F6810"; + break; case MV_DEV_MV78100_Z0: dev = "Marvell MV78100 Z0"; break; case MV_DEV_MV78100: dev = "Marvell MV78100"; break; case MV_DEV_MV78160: dev = "Marvell MV78160"; break; case MV_DEV_MV78260: dev = "Marvell MV78260"; break; case MV_DEV_MV78460: dev = "Marvell MV78460"; break; default: dev = "UNKNOWN"; break; } printf("%s", dev); if (*rev != '\0') printf(" rev %s", rev); printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000); mode = read_cpu_ctrl(CPU_CONFIG); printf(" Instruction cache prefetch %s, data cache prefetch %s\n", (mode & CPU_CONFIG_IC_PREF) ? "enabled" : "disabled", (mode & CPU_CONFIG_DC_PREF) ? "enabled" : "disabled"); switch (d) { case MV_DEV_88F6281: case MV_DEV_88F6282: mode = read_cpu_ctrl(CPU_L2_CONFIG) & CPU_L2_CONFIG_MODE; printf(" 256KB 4-way set-associative %s unified L2 cache\n", mode ? "write-through" : "write-back"); break; case MV_DEV_MV78100: mode = read_cpu_ctrl(CPU_CONTROL); size = mode & CPU_CONTROL_L2_SIZE; mode = mode & CPU_CONTROL_L2_MODE; printf(" %s set-associative %s unified L2 cache\n", size ? "256KB 4-way" : "512KB 8-way", mode ? "write-through" : "write-back"); break; default: break; } } static void platform_identify(void *dummy) { soc_identify(); /* * XXX Board identification e.g. read out from FPGA or similar should * go here */ } SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL); #ifdef KDB static void mv_enter_debugger(void *dummy) { if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); } SYSINIT(mv_enter_debugger, SI_SUB_CPU, SI_ORDER_ANY, mv_enter_debugger, NULL); #endif int soc_decode_win(void) { uint32_t dev, rev; int mask, err; mask = 0; TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask); if (mask != 0) pm_disable_device(mask); /* Retrieve data about physical addresses from device tree. */ if ((err = win_cpu_from_dt()) != 0) return (err); /* Retrieve our ID: some windows facilities vary between SoC models */ soc_id(&dev, &rev); #ifdef SOC_MV_ARMADAXP if ((err = decode_win_sdram_fixup()) != 0) return(err); #endif #ifndef SOC_MV_FREY if (!decode_win_cpu_valid() || !decode_win_usb_valid() || !decode_win_eth_valid() || !decode_win_idma_valid() || !decode_win_pcie_valid() || !decode_win_sata_valid() || !decode_win_xor_valid()) return (EINVAL); decode_win_cpu_setup(); #else if (!decode_win_usb_valid() || !decode_win_eth_valid() || !decode_win_idma_valid() || !decode_win_pcie_valid() || !decode_win_sata_valid() || !decode_win_xor_valid()) return (EINVAL); #endif if (MV_DUMP_WIN) soc_dump_decode_win(); eth_port = 0; usb_port = 0; if ((err = fdt_win_setup()) != 0) return (err); return (0); } /************************************************************************** * Decode windows registers accessors **************************************************************************/ #if !defined(SOC_MV_FREY) WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) #endif WIN_REG_BASE_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL) WIN_REG_BASE_IDX_RD(win_usb, br, MV_WIN_USB_BASE) WIN_REG_BASE_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL) WIN_REG_BASE_IDX_WR(win_usb, br, MV_WIN_USB_BASE) WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE) WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE) WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP) WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE) WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE) WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP) WIN_REG_BASE_IDX_RD2(win_xor, br, MV_WIN_XOR_BASE) WIN_REG_BASE_IDX_RD2(win_xor, sz, MV_WIN_XOR_SIZE) WIN_REG_BASE_IDX_RD2(win_xor, har, MV_WIN_XOR_REMAP) WIN_REG_BASE_IDX_RD2(win_xor, ctrl, MV_WIN_XOR_CTRL) WIN_REG_BASE_IDX_WR2(win_xor, br, MV_WIN_XOR_BASE) WIN_REG_BASE_IDX_WR2(win_xor, sz, MV_WIN_XOR_SIZE) WIN_REG_BASE_IDX_WR2(win_xor, har, MV_WIN_XOR_REMAP) WIN_REG_BASE_IDX_WR2(win_xor, ctrl, MV_WIN_XOR_CTRL) WIN_REG_BASE_RD(win_eth, bare, 0x290) WIN_REG_BASE_RD(win_eth, epap, 0x294) WIN_REG_BASE_WR(win_eth, bare, 0x290) WIN_REG_BASE_WR(win_eth, epap, 0x294) WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL); WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE); WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP); WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL); WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE); WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP); WIN_REG_BASE_IDX_RD(pcie_bar, br, MV_PCIE_BAR_BASE); WIN_REG_BASE_IDX_WR(pcie_bar, br, MV_PCIE_BAR_BASE); WIN_REG_BASE_IDX_WR(pcie_bar, brh, MV_PCIE_BAR_BASE_H); WIN_REG_BASE_IDX_WR(pcie_bar, cr, MV_PCIE_BAR_CTRL); WIN_REG_BASE_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE) WIN_REG_BASE_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE) WIN_REG_BASE_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP) WIN_REG_BASE_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP) WIN_REG_BASE_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE) WIN_REG_BASE_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE) WIN_REG_BASE_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP) WIN_REG_BASE_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP) WIN_REG_BASE_RD(win_idma, bare, 0xa80) WIN_REG_BASE_WR(win_idma, bare, 0xa80) WIN_REG_BASE_IDX_RD(win_sata, cr, MV_WIN_SATA_CTRL); WIN_REG_BASE_IDX_RD(win_sata, br, MV_WIN_SATA_BASE); WIN_REG_BASE_IDX_WR(win_sata, cr, MV_WIN_SATA_CTRL); WIN_REG_BASE_IDX_WR(win_sata, br, MV_WIN_SATA_BASE); #ifndef SOC_MV_DOVE WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) WIN_REG_IDX_WR(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) WIN_REG_IDX_WR(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) #else /* * On 88F6781 (Dove) SoC DDR Controller is accessed through * single MBUS <-> AXI bridge. In this case we provide emulated * ddr_br_read() and ddr_sz_read() functions to keep compatibility * with common decoding windows setup code. */ static inline uint32_t ddr_br_read(int i) { uint32_t mmap; /* Read Memory Address Map Register for CS i */ mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); /* Return CS i base address */ return (mmap & 0xFF000000); } static inline uint32_t ddr_sz_read(int i) { uint32_t mmap, size; /* Read Memory Address Map Register for CS i */ mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); /* Extract size of CS space in 64kB units */ size = (1 << ((mmap >> 16) & 0x0F)); /* Return CS size and enable/disable status */ return (((size - 1) << 16) | (mmap & 0x01)); } #endif #if !defined(SOC_MV_FREY) /************************************************************************** * Decode windows helper routines **************************************************************************/ void soc_dump_decode_win(void) { uint32_t dev, rev; int i; soc_id(&dev, &rev); for (i = 0; i < MV_WIN_CPU_MAX; i++) { printf("CPU window#%d: c 0x%08x, b 0x%08x", i, win_cpu_cr_read(i), win_cpu_br_read(i)); if (win_cpu_can_remap(i)) printf(", rl 0x%08x, rh 0x%08x", win_cpu_remap_l_read(i), win_cpu_remap_h_read(i)); printf("\n"); } printf("Internal regs base: 0x%08x\n", bus_space_read_4(fdtbus_bs_tag, MV_INTREGS_BASE, 0)); for (i = 0; i < MV_WIN_DDR_MAX; i++) printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i, ddr_br_read(i), ddr_sz_read(i)); } /************************************************************************** * CPU windows routines **************************************************************************/ int win_cpu_can_remap(int i) { uint32_t dev, rev; soc_id(&dev, &rev); /* Depending on the SoC certain windows have remap capability */ if ((dev == MV_DEV_88F5182 && i < 2) || (dev == MV_DEV_88F5281 && i < 4) || (dev == MV_DEV_88F6281 && i < 4) || (dev == MV_DEV_88F6282 && i < 4) || + (dev == MV_DEV_88F6828 && i < 20) || + (dev == MV_DEV_88F6820 && i < 20) || + (dev == MV_DEV_88F6810 && i < 20) || (dev == MV_DEV_88RC8180 && i < 2) || (dev == MV_DEV_88F6781 && i < 4) || (dev == MV_DEV_MV78100_Z0 && i < 8) || ((dev & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY && i < 8)) return (1); return (0); } /* XXX This should check for overlapping remap fields too.. */ int decode_win_overlap(int win, int win_no, const struct decode_win *wintab) { const struct decode_win *tab; int i; tab = wintab; for (i = 0; i < win_no; i++, tab++) { if (i == win) /* Skip self */ continue; if ((tab->base + tab->size - 1) < (wintab + win)->base) continue; else if (((wintab + win)->base + (wintab + win)->size - 1) < tab->base) continue; else return (i); } return (-1); } static int decode_win_cpu_valid(void) { int i, j, rv; uint32_t b, e, s; if (cpu_wins_no > MV_WIN_CPU_MAX) { printf("CPU windows: too many entries: %d\n", cpu_wins_no); return (0); } rv = 1; for (i = 0; i < cpu_wins_no; i++) { if (cpu_wins[i].target == 0) { printf("CPU window#%d: DDR target window is not " "supposed to be reprogrammed!\n", i); rv = 0; } if (cpu_wins[i].remap != ~0 && win_cpu_can_remap(i) != 1) { printf("CPU window#%d: not capable of remapping, but " "val 0x%08x defined\n", i, cpu_wins[i].remap); rv = 0; } s = cpu_wins[i].size; b = cpu_wins[i].base; e = b + s - 1; if (s > (0xFFFFFFFF - b + 1)) { /* * XXX this boundary check should account for 64bit * and remapping.. */ printf("CPU window#%d: no space for size 0x%08x at " "0x%08x\n", i, s, b); rv = 0; continue; } if (b != (b & ~(s - 1))) { printf("CPU window#%d: address 0x%08x is not aligned " "to 0x%08x\n", i, b, s); rv = 0; continue; } j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]); if (j >= 0) { printf("CPU window#%d: (0x%08x - 0x%08x) overlaps " "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, cpu_wins[j].base, cpu_wins[j].base + cpu_wins[j].size - 1); rv = 0; } } return (rv); } int decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, vm_paddr_t remap) { uint32_t br, cr; int win, i; if (remap == ~0) { win = MV_WIN_CPU_MAX - 1; i = -1; } else { win = 0; i = 1; } while ((win >= 0) && (win < MV_WIN_CPU_MAX)) { cr = win_cpu_cr_read(win); if ((cr & MV_WIN_CPU_ENABLE_BIT) == 0) break; if ((cr & ((0xff << MV_WIN_CPU_ATTR_SHIFT) | (0x1f << MV_WIN_CPU_TARGET_SHIFT))) == ((attr << MV_WIN_CPU_ATTR_SHIFT) | (target << MV_WIN_CPU_TARGET_SHIFT))) break; win += i; } if ((win < 0) || (win >= MV_WIN_CPU_MAX) || ((remap != ~0) && (win_cpu_can_remap(win) == 0))) return (-1); br = base & 0xffff0000; win_cpu_br_write(win, br); if (win_cpu_can_remap(win)) { if (remap != ~0) { win_cpu_remap_l_write(win, remap & 0xffff0000); win_cpu_remap_h_write(win, 0); } else { /* * Remap function is not used for a given window * (capable of remapping) - set remap field with the * same value as base. */ win_cpu_remap_l_write(win, base & 0xffff0000); win_cpu_remap_h_write(win, 0); } } cr = ((size - 1) & 0xffff0000) | (attr << MV_WIN_CPU_ATTR_SHIFT) | (target << MV_WIN_CPU_TARGET_SHIFT) | MV_WIN_CPU_ENABLE_BIT; win_cpu_cr_write(win, cr); return (0); } static void decode_win_cpu_setup(void) { int i; /* Disable all CPU windows */ for (i = 0; i < MV_WIN_CPU_MAX; i++) { win_cpu_cr_write(i, 0); win_cpu_br_write(i, 0); if (win_cpu_can_remap(i)) { win_cpu_remap_l_write(i, 0); win_cpu_remap_h_write(i, 0); } } for (i = 0; i < cpu_wins_no; i++) if (cpu_wins[i].target > 0) decode_win_cpu_set(cpu_wins[i].target, cpu_wins[i].attr, cpu_wins[i].base, cpu_wins[i].size, cpu_wins[i].remap); } #endif #ifdef SOC_MV_ARMADAXP static int decode_win_sdram_fixup(void) { struct mem_region mr[FDT_MEM_REGIONS]; uint8_t window_valid[MV_WIN_DDR_MAX]; int mr_cnt, memsize, err, i, j; uint32_t valid_win_num = 0; /* Grab physical memory regions information from device tree. */ err = fdt_get_mem_regions(mr, &mr_cnt, &memsize); if (err != 0) return (err); for (i = 0; i < MV_WIN_DDR_MAX; i++) window_valid[i] = 0; /* Try to match entries from device tree with settings from u-boot */ for (i = 0; i < mr_cnt; i++) { for (j = 0; j < MV_WIN_DDR_MAX; j++) { if (ddr_is_active(j) && (ddr_base(j) == mr[i].mr_start) && (ddr_size(j) == mr[i].mr_size)) { window_valid[j] = 1; valid_win_num++; } } } if (mr_cnt != valid_win_num) return (EINVAL); /* Destroy windows without corresponding device tree entry */ for (j = 0; j < MV_WIN_DDR_MAX; j++) { if (ddr_is_active(j) && (window_valid[j] != 1)) { printf("Disabling SDRAM decoding window: %d\n", j); ddr_disable(j); } } return (0); } #endif /* * Check if we're able to cover all active DDR banks. */ static int decode_win_can_cover_ddr(int max) { int i, c; c = 0; for (i = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) c++; if (c > max) { printf("Unable to cover all active DDR banks: " "%d, available windows: %d\n", c, max); return (0); } return (1); } /************************************************************************** * DDR windows routines **************************************************************************/ int ddr_is_active(int i) { if (ddr_sz_read(i) & 0x1) return (1); return (0); } void ddr_disable(int i) { ddr_sz_write(i, 0); ddr_br_write(i, 0); } uint32_t ddr_base(int i) { return (ddr_br_read(i) & 0xff000000); } uint32_t ddr_size(int i) { return ((ddr_sz_read(i) | 0x00ffffff) + 1); } uint32_t ddr_attr(int i) { uint32_t dev, rev; soc_id(&dev, &rev); if (dev == MV_DEV_88RC8180) return ((ddr_sz_read(i) & 0xf0) >> 4); if (dev == MV_DEV_88F6781) return (0); return (i == 0 ? 0xe : (i == 1 ? 0xd : (i == 2 ? 0xb : (i == 3 ? 0x7 : 0xff)))); } uint32_t ddr_target(int i) { uint32_t dev, rev; soc_id(&dev, &rev); if (dev == MV_DEV_88RC8180) { i = (ddr_sz_read(i) & 0xf0) >> 4; return (i == 0xe ? 0xc : (i == 0xd ? 0xd : (i == 0xb ? 0xe : (i == 0x7 ? 0xf : 0xc)))); } /* * On SOCs other than 88RC8180 Mbus unit ID for * DDR SDRAM controller is always 0x0. */ return (0); } /************************************************************************** * USB windows routines **************************************************************************/ static int decode_win_usb_valid(void) { return (decode_win_can_cover_ddr(MV_WIN_USB_MAX)); } static void decode_win_usb_dump(u_long base) { int i; if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port - 1))) return; for (i = 0; i < MV_WIN_USB_MAX; i++) printf("USB window#%d: c 0x%08x, b 0x%08x\n", i, win_usb_cr_read(base, i), win_usb_br_read(base, i)); } /* * Set USB decode windows. */ static void decode_win_usb_setup(u_long base) { uint32_t br, cr; int i, j; if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port))) return; usb_port++; for (i = 0; i < MV_WIN_USB_MAX; i++) { win_usb_cr_write(base, i, 0); win_usb_br_write(base, i, 0); } /* Only access to active DRAM banks is required */ for (i = 0; i < MV_WIN_DDR_MAX; i++) { if (ddr_is_active(i)) { br = ddr_base(i); /* * XXX for 6281 we should handle Mbus write * burst limit field in the ctrl reg */ cr = (((ddr_size(i) - 1) & 0xffff0000) | (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1); /* Set the first free USB window */ for (j = 0; j < MV_WIN_USB_MAX; j++) { if (win_usb_cr_read(base, j) & 0x1) continue; win_usb_br_write(base, j, br); win_usb_cr_write(base, j, cr); break; } } } } /************************************************************************** * ETH windows routines **************************************************************************/ static int win_eth_can_remap(int i) { /* ETH encode windows 0-3 have remap capability */ if (i < 4) return (1); return (0); } static int eth_bare_read(uint32_t base, int i) { uint32_t v; v = win_eth_bare_read(base); v &= (1 << i); return (v >> i); } static void eth_bare_write(uint32_t base, int i, int val) { uint32_t v; v = win_eth_bare_read(base); v &= ~(1 << i); v |= (val << i); win_eth_bare_write(base, v); } static void eth_epap_write(uint32_t base, int i, int val) { uint32_t v; v = win_eth_epap_read(base); v &= ~(0x3 << (i * 2)); v |= (val << (i * 2)); win_eth_epap_write(base, v); } static void decode_win_eth_dump(u_long base) { int i; if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port - 1))) return; for (i = 0; i < MV_WIN_ETH_MAX; i++) { printf("ETH window#%d: b 0x%08x, s 0x%08x", i, win_eth_br_read(base, i), win_eth_sz_read(base, i)); if (win_eth_can_remap(i)) printf(", ha 0x%08x", win_eth_har_read(base, i)); printf("\n"); } printf("ETH windows: bare 0x%08x, epap 0x%08x\n", win_eth_bare_read(base), win_eth_epap_read(base)); } #if defined(SOC_MV_LOKIPLUS) #define MV_WIN_ETH_DDR_TRGT(n) 0 #else #define MV_WIN_ETH_DDR_TRGT(n) ddr_target(n) #endif static void decode_win_eth_setup(u_long base) { uint32_t br, sz; int i, j; if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port))) return; eth_port++; /* Disable, clear and revoke protection for all ETH windows */ for (i = 0; i < MV_WIN_ETH_MAX; i++) { eth_bare_write(base, i, 1); eth_epap_write(base, i, 0); win_eth_br_write(base, i, 0); win_eth_sz_write(base, i, 0); if (win_eth_can_remap(i)) win_eth_har_write(base, i, 0); } /* Only access to active DRAM banks is required */ for (i = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) { br = ddr_base(i) | (ddr_attr(i) << 8) | MV_WIN_ETH_DDR_TRGT(i); sz = ((ddr_size(i) - 1) & 0xffff0000); /* Set the first free ETH window */ for (j = 0; j < MV_WIN_ETH_MAX; j++) { if (eth_bare_read(base, j) == 0) continue; win_eth_br_write(base, j, br); win_eth_sz_write(base, j, sz); /* XXX remapping ETH windows not supported */ /* Set protection RW */ eth_epap_write(base, j, 0x3); /* Enable window */ eth_bare_write(base, j, 0); break; } } } static int decode_win_eth_valid(void) { return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX)); } /************************************************************************** * PCIE windows routines **************************************************************************/ void decode_win_pcie_setup(u_long base) { uint32_t size = 0, ddrbase = ~0; uint32_t cr, br; int i, j; for (i = 0; i < MV_PCIE_BAR_MAX; i++) { pcie_bar_br_write(base, i, MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); if (i < 3) pcie_bar_brh_write(base, i, 0); if (i > 0) pcie_bar_cr_write(base, i, 0); } for (i = 0; i < MV_WIN_PCIE_MAX; i++) { win_pcie_cr_write(base, i, 0); win_pcie_br_write(base, i, 0); win_pcie_remap_write(base, i, 0); } /* On End-Point only set BAR size to 1MB regardless of DDR size */ if ((bus_space_read_4(fdtbus_bs_tag, base, MV_PCIE_CONTROL) & MV_PCIE_ROOT_CMPLX) == 0) { pcie_bar_cr_write(base, 1, 0xf0000 | 1); return; } for (i = 0; i < MV_WIN_DDR_MAX; i++) { if (ddr_is_active(i)) { /* Map DDR to BAR 1 */ cr = (ddr_size(i) - 1) & 0xffff0000; size += ddr_size(i) & 0xffff0000; cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; br = ddr_base(i); if (br < ddrbase) ddrbase = br; /* Use the first available PCIE window */ for (j = 0; j < MV_WIN_PCIE_MAX; j++) { if (win_pcie_cr_read(base, j) != 0) continue; win_pcie_br_write(base, j, br); win_pcie_cr_write(base, j, cr); break; } } } /* * Upper 16 bits in BAR register is interpreted as BAR size * (in 64 kB units) plus 64kB, so substract 0x10000 * form value passed to register to get correct value. */ size -= 0x10000; pcie_bar_cr_write(base, 1, size | 1); pcie_bar_br_write(base, 1, ddrbase | MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); pcie_bar_br_write(base, 0, fdt_immr_pa | MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); } static int decode_win_pcie_valid(void) { return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX)); } /************************************************************************** * IDMA windows routines **************************************************************************/ #if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY) static int idma_bare_read(u_long base, int i) { uint32_t v; v = win_idma_bare_read(base); v &= (1 << i); return (v >> i); } static void idma_bare_write(u_long base, int i, int val) { uint32_t v; v = win_idma_bare_read(base); v &= ~(1 << i); v |= (val << i); win_idma_bare_write(base, v); } /* * Sets channel protection 'val' for window 'w' on channel 'c' */ static void idma_cap_write(u_long base, int c, int w, int val) { uint32_t v; v = win_idma_cap_read(base, c); v &= ~(0x3 << (w * 2)); v |= (val << (w * 2)); win_idma_cap_write(base, c, v); } /* * Set protection 'val' on all channels for window 'w' */ static void idma_set_prot(u_long base, int w, int val) { int c; for (c = 0; c < MV_IDMA_CHAN_MAX; c++) idma_cap_write(base, c, w, val); } static int win_idma_can_remap(int i) { /* IDMA decode windows 0-3 have remap capability */ if (i < 4) return (1); return (0); } void decode_win_idma_setup(u_long base) { uint32_t br, sz; int i, j; if (pm_is_disabled(CPU_PM_CTRL_IDMA)) return; /* * Disable and clear all IDMA windows, revoke protection for all channels */ for (i = 0; i < MV_WIN_IDMA_MAX; i++) { idma_bare_write(base, i, 1); win_idma_br_write(base, i, 0); win_idma_sz_write(base, i, 0); if (win_idma_can_remap(i) == 1) win_idma_har_write(base, i, 0); } for (i = 0; i < MV_IDMA_CHAN_MAX; i++) win_idma_cap_write(base, i, 0); /* * Set up access to all active DRAM banks */ for (i = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) { br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); sz = ((ddr_size(i) - 1) & 0xffff0000); /* Place DDR entries in non-remapped windows */ for (j = 0; j < MV_WIN_IDMA_MAX; j++) if (win_idma_can_remap(j) != 1 && idma_bare_read(base, j) == 1) { /* Configure window */ win_idma_br_write(base, j, br); win_idma_sz_write(base, j, sz); /* Set protection RW on all channels */ idma_set_prot(base, j, 0x3); /* Enable window */ idma_bare_write(base, j, 0); break; } } /* * Remaining targets -- from statically defined table */ for (i = 0; i < idma_wins_no; i++) if (idma_wins[i].target > 0) { br = (idma_wins[i].base & 0xffff0000) | (idma_wins[i].attr << 8) | idma_wins[i].target; sz = ((idma_wins[i].size - 1) & 0xffff0000); /* Set the first free IDMA window */ for (j = 0; j < MV_WIN_IDMA_MAX; j++) { if (idma_bare_read(base, j) == 0) continue; /* Configure window */ win_idma_br_write(base, j, br); win_idma_sz_write(base, j, sz); if (win_idma_can_remap(j) && idma_wins[j].remap >= 0) win_idma_har_write(base, j, idma_wins[j].remap); /* Set protection RW on all channels */ idma_set_prot(base, j, 0x3); /* Enable window */ idma_bare_write(base, j, 0); break; } } } int decode_win_idma_valid(void) { const struct decode_win *wintab; int c, i, j, rv; uint32_t b, e, s; if (idma_wins_no > MV_WIN_IDMA_MAX) { printf("IDMA windows: too many entries: %d\n", idma_wins_no); return (0); } for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) c++; if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) { printf("IDMA windows: too many entries: %d, available: %d\n", idma_wins_no, MV_WIN_IDMA_MAX - c); return (0); } wintab = idma_wins; rv = 1; for (i = 0; i < idma_wins_no; i++, wintab++) { if (wintab->target == 0) { printf("IDMA window#%d: DDR target window is not " "supposed to be reprogrammed!\n", i); rv = 0; } if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { printf("IDMA window#%d: not capable of remapping, but " "val 0x%08x defined\n", i, wintab->remap); rv = 0; } s = wintab->size; b = wintab->base; e = b + s - 1; if (s > (0xFFFFFFFF - b + 1)) { /* XXX this boundary check should account for 64bit and * remapping.. */ printf("IDMA window#%d: no space for size 0x%08x at " "0x%08x\n", i, s, b); rv = 0; continue; } j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]); if (j >= 0) { printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps " "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, idma_wins[j].base, idma_wins[j].base + idma_wins[j].size - 1); rv = 0; } } return (rv); } void decode_win_idma_dump(u_long base) { int i; if (pm_is_disabled(CPU_PM_CTRL_IDMA)) return; for (i = 0; i < MV_WIN_IDMA_MAX; i++) { printf("IDMA window#%d: b 0x%08x, s 0x%08x", i, win_idma_br_read(base, i), win_idma_sz_read(base, i)); if (win_idma_can_remap(i)) printf(", ha 0x%08x", win_idma_har_read(base, i)); printf("\n"); } for (i = 0; i < MV_IDMA_CHAN_MAX; i++) printf("IDMA channel#%d: ap 0x%08x\n", i, win_idma_cap_read(base, i)); printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read(base)); } #else /* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */ int decode_win_idma_valid(void) { return (1); } void decode_win_idma_setup(u_long base) { } void decode_win_idma_dump(u_long base) { } #endif /************************************************************************** * XOR windows routines **************************************************************************/ #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) static int xor_ctrl_read(u_long base, int i, int c, int e) { uint32_t v; v = win_xor_ctrl_read(base, c, e); v &= (1 << i); return (v >> i); } static void xor_ctrl_write(u_long base, int i, int c, int e, int val) { uint32_t v; v = win_xor_ctrl_read(base, c, e); v &= ~(1 << i); v |= (val << i); win_xor_ctrl_write(base, c, e, v); } /* * Set channel protection 'val' for window 'w' on channel 'c' */ static void xor_chan_write(u_long base, int c, int e, int w, int val) { uint32_t v; v = win_xor_ctrl_read(base, c, e); v &= ~(0x3 << (w * 2 + 16)); v |= (val << (w * 2 + 16)); win_xor_ctrl_write(base, c, e, v); } /* * Set protection 'val' on all channels for window 'w' on engine 'e' */ static void xor_set_prot(u_long base, int w, int e, int val) { int c; for (c = 0; c < MV_XOR_CHAN_MAX; c++) xor_chan_write(base, c, e, w, val); } static int win_xor_can_remap(int i) { /* XOR decode windows 0-3 have remap capability */ if (i < 4) return (1); return (0); } static int xor_max_eng(void) { uint32_t dev, rev; soc_id(&dev, &rev); switch (dev) { case MV_DEV_88F6281: case MV_DEV_88F6282: case MV_DEV_MV78130: case MV_DEV_MV78160: case MV_DEV_MV78230: case MV_DEV_MV78260: case MV_DEV_MV78460: return (2); case MV_DEV_MV78100: case MV_DEV_MV78100_Z0: return (1); default: return (0); } } static void xor_active_dram(u_long base, int c, int e, int *window) { uint32_t br, sz; int i, m, w; /* * Set up access to all active DRAM banks */ m = xor_max_eng(); for (i = 0; i < m; i++) if (ddr_is_active(i)) { br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); sz = ((ddr_size(i) - 1) & 0xffff0000); /* Place DDR entries in non-remapped windows */ for (w = 0; w < MV_WIN_XOR_MAX; w++) if (win_xor_can_remap(w) != 1 && (xor_ctrl_read(base, w, c, e) == 0) && w > *window) { /* Configure window */ win_xor_br_write(base, w, e, br); win_xor_sz_write(base, w, e, sz); /* Set protection RW on all channels */ xor_set_prot(base, w, e, 0x3); /* Enable window */ xor_ctrl_write(base, w, c, e, 1); (*window)++; break; } } } void decode_win_xor_setup(u_long base) { uint32_t br, sz; int i, j, z, e = 1, m, window; if (pm_is_disabled(CPU_PM_CTRL_XOR)) return; /* * Disable and clear all XOR windows, revoke protection for all * channels */ m = xor_max_eng(); for (j = 0; j < m; j++, e--) { /* Number of non-remaped windows */ window = MV_XOR_NON_REMAP - 1; for (i = 0; i < MV_WIN_XOR_MAX; i++) { win_xor_br_write(base, i, e, 0); win_xor_sz_write(base, i, e, 0); } if (win_xor_can_remap(i) == 1) win_xor_har_write(base, i, e, 0); for (i = 0; i < MV_XOR_CHAN_MAX; i++) { win_xor_ctrl_write(base, i, e, 0); xor_active_dram(base, i, e, &window); } /* * Remaining targets -- from a statically defined table */ for (i = 0; i < xor_wins_no; i++) if (xor_wins[i].target > 0) { br = (xor_wins[i].base & 0xffff0000) | (xor_wins[i].attr << 8) | xor_wins[i].target; sz = ((xor_wins[i].size - 1) & 0xffff0000); /* Set the first free XOR window */ for (z = 0; z < MV_WIN_XOR_MAX; z++) { if (xor_ctrl_read(base, z, 0, e) && xor_ctrl_read(base, z, 1, e)) continue; /* Configure window */ win_xor_br_write(base, z, e, br); win_xor_sz_write(base, z, e, sz); if (win_xor_can_remap(z) && xor_wins[z].remap >= 0) win_xor_har_write(base, z, e, xor_wins[z].remap); /* Set protection RW on all channels */ xor_set_prot(base, z, e, 0x3); /* Enable window */ xor_ctrl_write(base, z, 0, e, 1); xor_ctrl_write(base, z, 1, e, 1); break; } } } } int decode_win_xor_valid(void) { const struct decode_win *wintab; int c, i, j, rv; uint32_t b, e, s; if (xor_wins_no > MV_WIN_XOR_MAX) { printf("XOR windows: too many entries: %d\n", xor_wins_no); return (0); } for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) c++; if (xor_wins_no > (MV_WIN_XOR_MAX - c)) { printf("XOR windows: too many entries: %d, available: %d\n", xor_wins_no, MV_WIN_IDMA_MAX - c); return (0); } wintab = xor_wins; rv = 1; for (i = 0; i < xor_wins_no; i++, wintab++) { if (wintab->target == 0) { printf("XOR window#%d: DDR target window is not " "supposed to be reprogrammed!\n", i); rv = 0; } if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { printf("XOR window#%d: not capable of remapping, but " "val 0x%08x defined\n", i, wintab->remap); rv = 0; } s = wintab->size; b = wintab->base; e = b + s - 1; if (s > (0xFFFFFFFF - b + 1)) { /* * XXX this boundary check should account for 64bit * and remapping.. */ printf("XOR window#%d: no space for size 0x%08x at " "0x%08x\n", i, s, b); rv = 0; continue; } j = decode_win_overlap(i, xor_wins_no, &xor_wins[0]); if (j >= 0) { printf("XOR window#%d: (0x%08x - 0x%08x) overlaps " "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, xor_wins[j].base, xor_wins[j].base + xor_wins[j].size - 1); rv = 0; } } return (rv); } void decode_win_xor_dump(u_long base) { int i, j; int e = 1; if (pm_is_disabled(CPU_PM_CTRL_XOR)) return; for (j = 0; j < xor_max_eng(); j++, e--) { for (i = 0; i < MV_WIN_XOR_MAX; i++) { printf("XOR window#%d: b 0x%08x, s 0x%08x", i, win_xor_br_read(base, i, e), win_xor_sz_read(base, i, e)); if (win_xor_can_remap(i)) printf(", ha 0x%08x", win_xor_har_read(base, i, e)); printf("\n"); } for (i = 0; i < MV_XOR_CHAN_MAX; i++) printf("XOR control#%d: 0x%08x\n", i, win_xor_ctrl_read(base, i, e)); } } #else /* Provide dummy functions to satisfy the build for SoCs not equipped with XOR */ static int decode_win_xor_valid(void) { return (1); } static void decode_win_xor_setup(u_long base) { } static void decode_win_xor_dump(u_long base) { } #endif /************************************************************************** * SATA windows routines **************************************************************************/ static void decode_win_sata_setup(u_long base) { uint32_t cr, br; int i, j; if (pm_is_disabled(CPU_PM_CTRL_SATA)) return; for (i = 0; i < MV_WIN_SATA_MAX; i++) { win_sata_cr_write(base, i, 0); win_sata_br_write(base, i, 0); } for (i = 0; i < MV_WIN_DDR_MAX; i++) if (ddr_is_active(i)) { cr = ((ddr_size(i) - 1) & 0xffff0000) | (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; br = ddr_base(i); /* Use the first available SATA window */ for (j = 0; j < MV_WIN_SATA_MAX; j++) { if ((win_sata_cr_read(base, j) & 1) != 0) continue; win_sata_br_write(base, j, br); win_sata_cr_write(base, j, cr); break; } } } static int decode_win_sata_valid(void) { uint32_t dev, rev; soc_id(&dev, &rev); if (dev == MV_DEV_88F5281) return (1); return (decode_win_can_cover_ddr(MV_WIN_SATA_MAX)); } /************************************************************************** * FDT parsing routines. **************************************************************************/ static int fdt_get_ranges(const char *nodename, void *buf, int size, int *tuples, int *tuplesize) { phandle_t node; pcell_t addr_cells, par_addr_cells, size_cells; int len, tuple_size, tuples_count; node = OF_finddevice(nodename); if (node == -1) return (EINVAL); if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) return (ENXIO); par_addr_cells = fdt_parent_addr_cells(node); if (par_addr_cells > 2) return (ERANGE); tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + size_cells); /* Note the OF_getprop_alloc() cannot be used at this early stage. */ len = OF_getprop(node, "ranges", buf, size); /* * XXX this does not handle the empty 'ranges;' case, which is * legitimate and should be allowed. */ tuples_count = len / tuple_size; if (tuples_count <= 0) return (ERANGE); if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) return (ERANGE); *tuples = tuples_count; *tuplesize = tuple_size; return (0); } static int win_cpu_from_dt(void) { pcell_t ranges[48]; phandle_t node; int i, entry_size, err, t, tuple_size, tuples; u_long sram_base, sram_size; t = 0; /* Retrieve 'ranges' property of '/localbus' node. */ if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges), &tuples, &tuple_size)) == 0) { /* * Fill CPU decode windows table. */ bzero((void *)&cpu_win_tbl, sizeof(cpu_win_tbl)); entry_size = tuple_size / sizeof(pcell_t); cpu_wins_no = tuples; for (i = 0, t = 0; t < tuples; i += entry_size, t++) { cpu_win_tbl[t].target = 1; cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]); cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]); cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]); cpu_win_tbl[t].remap = ~0; debugf("target = 0x%0x attr = 0x%0x base = 0x%0x " "size = 0x%0x remap = 0x%0x\n", cpu_win_tbl[t].target, cpu_win_tbl[t].attr, cpu_win_tbl[t].base, cpu_win_tbl[t].size, cpu_win_tbl[t].remap); } } /* * Retrieve CESA SRAM data. */ if ((node = OF_finddevice("sram")) != -1) if (fdt_is_compatible(node, "mrvl,cesa-sram")) goto moveon; if ((node = OF_finddevice("/")) == 0) return (ENXIO); if ((node = fdt_find_compatible(node, "mrvl,cesa-sram", 0)) == 0) /* SRAM block is not always present. */ return (0); moveon: sram_base = sram_size = 0; if (fdt_regsize(node, &sram_base, &sram_size) != 0) return (EINVAL); cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); cpu_win_tbl[t].base = sram_base; cpu_win_tbl[t].size = sram_size; cpu_win_tbl[t].remap = ~0; cpu_wins_no++; debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); return (0); } static int fdt_win_setup(void) { phandle_t node, child; struct soc_node_spec *soc_node; u_long size, base; int err, i; node = OF_finddevice("/"); if (node == -1) panic("fdt_win_setup: no root node"); /* * Traverse through all children of root and simple-bus nodes. * For each found device retrieve decode windows data (if applicable). */ child = OF_child(node); while (child != 0) { for (i = 0; soc_nodes[i].compat != NULL; i++) { soc_node = &soc_nodes[i]; if (!fdt_is_compatible(child, soc_node->compat)) continue; err = fdt_regsize(child, &base, &size); if (err != 0) return (err); base = (base & 0x000fffff) | fdt_immr_va; if (soc_node->decode_handler != NULL) soc_node->decode_handler(base); else return (ENXIO); if (MV_DUMP_WIN && (soc_node->dump_handler != NULL)) soc_node->dump_handler(base); } /* * Once done with root-level children let's move down to * simple-bus and its children. */ child = OF_peer(child); if ((child == 0) && (node == OF_finddevice("/"))) { - node = fdt_find_compatible(node, "simple-bus", 1); + node = fdt_find_compatible(node, "simple-bus", 0); if (node == 0) return (ENXIO); child = OF_child(node); } } return (0); } static void fdt_fixup_busfreq(phandle_t root) { phandle_t sb; pcell_t freq; freq = cpu_to_fdt32(get_tclk()); /* * Fix bus speed in cpu node */ if ((sb = OF_finddevice("cpu")) != 0) if (fdt_is_compatible_strict(sb, "ARM,88VS584")) OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq)); /* * This fixup sets the simple-bus bus-frequency property. */ if ((sb = fdt_find_compatible(root, "simple-bus", 1)) != 0) OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq)); } static void fdt_fixup_ranges(phandle_t root) { phandle_t node; pcell_t par_addr_cells, addr_cells, size_cells; pcell_t ranges[3], reg[2], *rangesptr; int len, tuple_size, tuples_count; uint32_t base; /* Fix-up SoC ranges according to real fdt_immr_pa */ if ((node = fdt_find_compatible(root, "simple-bus", 1)) != 0) { if (fdt_addrsize_cells(node, &addr_cells, &size_cells) == 0 && (par_addr_cells = fdt_parent_addr_cells(node) <= 2)) { tuple_size = sizeof(pcell_t) * (par_addr_cells + addr_cells + size_cells); len = OF_getprop(node, "ranges", ranges, sizeof(ranges)); tuples_count = len / tuple_size; /* Unexpected settings are not supported */ if (tuples_count != 1) goto fixup_failed; rangesptr = &ranges[0]; rangesptr += par_addr_cells; base = fdt_data_get((void *)rangesptr, addr_cells); *rangesptr = cpu_to_fdt32(fdt_immr_pa); if (OF_setprop(node, "ranges", (void *)&ranges[0], sizeof(ranges)) < 0) goto fixup_failed; } } /* Fix-up PCIe reg according to real PCIe registers' PA */ if ((node = fdt_find_compatible(root, "mrvl,pcie", 1)) != 0) { if (fdt_addrsize_cells(OF_parent(node), &par_addr_cells, &size_cells) == 0) { tuple_size = sizeof(pcell_t) * (par_addr_cells + size_cells); len = OF_getprop(node, "reg", reg, sizeof(reg)); tuples_count = len / tuple_size; /* Unexpected settings are not supported */ if (tuples_count != 1) goto fixup_failed; base = fdt_data_get((void *)®[0], par_addr_cells); base &= ~0xFF000000; base |= fdt_immr_pa; reg[0] = cpu_to_fdt32(base); if (OF_setprop(node, "reg", (void *)®[0], sizeof(reg)) < 0) goto fixup_failed; } } /* Fix-up succeeded. May return and continue */ return; fixup_failed: while (1) { /* * In case of any error while fixing ranges just hang. * 1. No message can be displayed yet since console * is not initialized. * 2. Going further will cause failure on bus_space_map() * relying on the wrong ranges or data abort when * accessing PCIe registers. */ } } struct fdt_fixup_entry fdt_fixup_table[] = { { "mrvl,DB-88F6281", &fdt_fixup_busfreq }, { "mrvl,DB-78460", &fdt_fixup_busfreq }, { "mrvl,DB-78460", &fdt_fixup_ranges }, { NULL, NULL } }; static int fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, int *pol) { if (!fdt_is_compatible(node, "mrvl,pic") && !fdt_is_compatible(node, "mrvl,mpic")) return (ENXIO); *interrupt = fdt32_to_cpu(intr[0]); *trig = INTR_TRIGGER_CONFORM; *pol = INTR_POLARITY_CONFORM; return (0); } fdt_pic_decode_t fdt_pic_table[] = { +#ifdef SOC_MV_ARMADA38X + &gic_decode_fdt, +#endif &fdt_pic_decode_ic, NULL }; uint64_t get_sar_value(void) { uint32_t sar_low, sar_high; #if defined(SOC_MV_ARMADAXP) sar_high = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, SAMPLE_AT_RESET_HI); sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, SAMPLE_AT_RESET_LO); +#elif defined(SOC_MV_ARMADA38X) + sar_high = 0; + sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, + SAMPLE_AT_RESET); #else /* * TODO: Add getting proper values for other SoC configurations */ sar_high = 0; sar_low = 0; #endif return (((uint64_t)sar_high << 32) | sar_low); } Index: projects/release-pkg/sys/arm/mv/mv_machdep.c =================================================================== --- projects/release-pkg/sys/arm/mv/mv_machdep.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/mv_machdep.c (revision 294448) @@ -1,486 +1,504 @@ /*- * Copyright (c) 1994-1998 Mark Brinicombe. * Copyright (c) 1994 Brini. * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Brini. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45 */ #include "opt_ddb.h" #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #define _ARM32_BUS_DMA_PRIVATE #include #include #include #include #include #include #include #include #include #include #include /* XXX */ #include /* XXX eventually this should be eliminated */ #include #include static int platform_mpp_init(void); #if defined(SOC_MV_ARMADAXP) void armadaxp_init_coher_fabric(void); void armadaxp_l2_init(void); #endif +#if defined(SOC_MV_ARMADA38X) +int armada38x_win_set_iosync_barrier(void); +int armada38x_scu_enable(void); +int armada38x_open_bootrom_win(void); +#endif #define MPP_PIN_MAX 68 #define MPP_PIN_CELLS 2 #define MPP_PINS_PER_REG 8 #define MPP_SEL(pin,func) (((func) & 0xf) << \ (((pin) % MPP_PINS_PER_REG) * 4)) static int platform_mpp_init(void) { pcell_t pinmap[MPP_PIN_MAX * MPP_PIN_CELLS]; int mpp[MPP_PIN_MAX]; uint32_t ctrl_val, ctrl_offset; pcell_t reg[4]; u_long start, size; phandle_t node; pcell_t pin_cells, *pinmap_ptr, pin_count; ssize_t len; int par_addr_cells, par_size_cells; int tuple_size, tuples, rv, pins, i, j; int mpp_pin, mpp_function; /* * Try to access the MPP node directly i.e. through /aliases/mpp. */ if ((node = OF_finddevice("mpp")) != -1) if (fdt_is_compatible(node, "mrvl,mpp")) goto moveon; /* * Find the node the long way. */ if ((node = OF_finddevice("/")) == -1) return (ENXIO); if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0) return (ENXIO); if ((node = fdt_find_compatible(node, "mrvl,mpp", 0)) == 0) /* * No MPP node. Fall back to how MPP got set by the * first-stage loader and try to continue booting. */ return (0); moveon: /* * Process 'reg' prop. */ if ((rv = fdt_addrsize_cells(OF_parent(node), &par_addr_cells, &par_size_cells)) != 0) return(ENXIO); tuple_size = sizeof(pcell_t) * (par_addr_cells + par_size_cells); len = OF_getprop(node, "reg", reg, sizeof(reg)); tuples = len / tuple_size; if (tuple_size <= 0) return (EINVAL); /* * Get address/size. XXX we assume only the first 'reg' tuple is used. */ rv = fdt_data_to_res(reg, par_addr_cells, par_size_cells, &start, &size); if (rv != 0) return (rv); start += fdt_immr_va; /* * Process 'pin-count' and 'pin-map' props. */ if (OF_getprop(node, "pin-count", &pin_count, sizeof(pin_count)) <= 0) return (ENXIO); pin_count = fdt32_to_cpu(pin_count); if (pin_count > MPP_PIN_MAX) return (ERANGE); if (OF_getprop(node, "#pin-cells", &pin_cells, sizeof(pin_cells)) <= 0) pin_cells = MPP_PIN_CELLS; pin_cells = fdt32_to_cpu(pin_cells); if (pin_cells > MPP_PIN_CELLS) return (ERANGE); tuple_size = sizeof(pcell_t) * pin_cells; bzero(pinmap, sizeof(pinmap)); len = OF_getprop(node, "pin-map", pinmap, sizeof(pinmap)); if (len <= 0) return (ERANGE); if (len % tuple_size) return (ERANGE); pins = len / tuple_size; if (pins > pin_count) return (ERANGE); /* * Fill out a "mpp[pin] => function" table. All pins unspecified in * the 'pin-map' property are defaulted to 0 function i.e. GPIO. */ bzero(mpp, sizeof(mpp)); pinmap_ptr = pinmap; for (i = 0; i < pins; i++) { mpp_pin = fdt32_to_cpu(*pinmap_ptr); mpp_function = fdt32_to_cpu(*(pinmap_ptr + 1)); mpp[mpp_pin] = mpp_function; pinmap_ptr += pin_cells; } /* * Prepare and program MPP control register values. */ ctrl_offset = 0; for (i = 0; i < pin_count;) { ctrl_val = 0; for (j = 0; j < MPP_PINS_PER_REG; j++) { if (i + j == pin_count - 1) break; ctrl_val |= MPP_SEL(i + j, mpp[i + j]); } i += MPP_PINS_PER_REG; bus_space_write_4(fdtbus_bs_tag, start, ctrl_offset, ctrl_val); #if defined(SOC_MV_ORION) /* * Third MPP reg on Orion SoC is placed * non-linearly (with different offset). */ if (i == (2 * MPP_PINS_PER_REG)) ctrl_offset = 0x50; else #endif ctrl_offset += 4; } return (0); } vm_offset_t platform_lastaddr(void) { return (fdt_immr_va); } void platform_probe_and_attach(void) { if (fdt_immr_addr(MV_BASE) != 0) while (1); } void platform_gpio_init(void) { /* * Re-initialise MPP. It is important to call this prior to using * console as the physical connection can be routed via MPP. */ if (platform_mpp_init() != 0) while (1); } void platform_late_init(void) { /* * Re-initialise decode windows */ #if !defined(SOC_MV_FREY) if (soc_decode_win() != 0) printf("WARNING: could not re-initialise decode windows! " "Running with existing settings...\n"); #else /* Disable watchdog and timers */ write_cpu_ctrl(CPU_TIMERS_BASE + CPU_TIMER_CONTROL, 0); #endif #if defined(SOC_MV_ARMADAXP) #if !defined(SMP) /* For SMP case it should be initialized after APs are booted */ armadaxp_init_coher_fabric(); #endif armadaxp_l2_init(); +#endif + +#if defined(SOC_MV_ARMADA38X) + /* Set IO Sync Barrier bit for all Mbus devices */ + if (armada38x_win_set_iosync_barrier() != 0) + printf("WARNING: could not map CPU Subsystem registers\n"); + if (armada38x_scu_enable() != 0) + printf("WARNING: could not enable SCU\n"); +#ifdef SMP + /* Open window to bootROM memory - needed for SMP */ + if (armada38x_open_bootrom_win() != 0) + printf("WARNING: could not open window to bootROM\n"); +#endif #endif } #define FDT_DEVMAP_MAX (MV_WIN_CPU_MAX + 2) static struct arm_devmap_entry fdt_devmap[FDT_DEVMAP_MAX] = { { 0, 0, 0, 0, 0, } }; static int platform_sram_devmap(struct arm_devmap_entry *map) { #if !defined(SOC_MV_ARMADAXP) phandle_t child, root; u_long base, size; /* * SRAM range. */ if ((child = OF_finddevice("/sram")) != 0) if (fdt_is_compatible(child, "mrvl,cesa-sram") || fdt_is_compatible(child, "mrvl,scratchpad")) goto moveon; if ((root = OF_finddevice("/")) == 0) return (ENXIO); if ((child = fdt_find_compatible(root, "mrvl,cesa-sram", 0)) == 0 && (child = fdt_find_compatible(root, "mrvl,scratchpad", 0)) == 0) goto out; moveon: if (fdt_regsize(child, &base, &size) != 0) return (EINVAL); map->pd_va = MV_CESA_SRAM_BASE; /* XXX */ map->pd_pa = base; map->pd_size = size; map->pd_prot = VM_PROT_READ | VM_PROT_WRITE; map->pd_cache = PTE_DEVICE; return (0); out: #endif return (ENOENT); } /* * Supply a default do-nothing implementation of mv_pci_devmap() via a weak * alias. Many Marvell platforms don't support a PCI interface, but to support * those that do, we end up with a reference to this function below, in * platform_devmap_init(). If "device pci" appears in the kernel config, the * real implementation of this function in arm/mv/mv_pci.c overrides the weak * alias defined here. */ int mv_default_fdt_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_va, vm_offset_t mem_va); int mv_default_fdt_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_va, vm_offset_t mem_va) { return (0); } __weak_reference(mv_default_fdt_pci_devmap, mv_pci_devmap); /* * XXX: When device entry in devmap has pd_size smaller than section size, * system will freeze during initialization */ /* * Construct pmap_devmap[] with DT-derived config data. */ int platform_devmap_init(void) { phandle_t root, child; pcell_t bank_count; int i, num_mapped; i = 0; arm_devmap_register_table(&fdt_devmap[0]); #ifdef SOC_MV_ARMADAXP vm_paddr_t cur_immr_pa; /* * Acquire SoC registers' base passed by u-boot and fill devmap * accordingly. DTB is going to be modified basing on this data * later. */ __asm __volatile("mrc p15, 4, %0, c15, c0, 0" : "=r" (cur_immr_pa)); cur_immr_pa = (cur_immr_pa << 13) & 0xff000000; if (cur_immr_pa != 0) fdt_immr_pa = cur_immr_pa; #endif /* * IMMR range. */ fdt_devmap[i].pd_va = fdt_immr_va; fdt_devmap[i].pd_pa = fdt_immr_pa; fdt_devmap[i].pd_size = fdt_immr_size; fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE; fdt_devmap[i].pd_cache = PTE_DEVICE; i++; /* * SRAM range. */ if (i < FDT_DEVMAP_MAX) if (platform_sram_devmap(&fdt_devmap[i]) == 0) i++; /* * PCI range(s). * PCI range(s) and localbus. */ if ((root = OF_finddevice("/")) == -1) return (ENXIO); for (child = OF_child(root); child != 0; child = OF_peer(child)) { if (fdt_is_type(child, "pci") || fdt_is_type(child, "pciep")) { /* * Check space: each PCI node will consume 2 devmap * entries. */ if (i + 1 >= FDT_DEVMAP_MAX) return (ENOMEM); /* * XXX this should account for PCI and multiple ranges * of a given kind. */ if (mv_pci_devmap(child, &fdt_devmap[i], MV_PCI_VA_IO_BASE, MV_PCI_VA_MEM_BASE) != 0) return (ENXIO); i += 2; } if (fdt_is_compatible(child, "mrvl,lbc")) { /* Check available space */ if (OF_getprop(child, "bank-count", (void *)&bank_count, sizeof(bank_count)) <= 0) /* If no property, use default value */ bank_count = 1; else bank_count = fdt32_to_cpu(bank_count); if ((i + bank_count) >= FDT_DEVMAP_MAX) return (ENOMEM); /* Add all localbus ranges to device map */ num_mapped = 0; if (fdt_localbus_devmap(child, &fdt_devmap[i], (int)bank_count, &num_mapped) != 0) return (ENXIO); i += num_mapped; } } return (0); } struct arm32_dma_range * bus_dma_get_range(void) { return (NULL); } int bus_dma_get_range_nb(void) { return (0); } #if defined(CPU_MV_PJ4B) #ifdef DDB #include DB_SHOW_COMMAND(cp15, db_show_cp15) { u_int reg; __asm __volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (reg)); db_printf("Cpu ID: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (reg)); db_printf("Current Cache Lvl ID: 0x%08x\n",reg); __asm __volatile("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg)); db_printf("Ctrl: 0x%08x\n",reg); __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (reg)); db_printf("Aux Ctrl: 0x%08x\n",reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 0" : "=r" (reg)); db_printf("Processor Feat 0: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 1" : "=r" (reg)); db_printf("Processor Feat 1: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 2" : "=r" (reg)); db_printf("Debug Feat 0: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 3" : "=r" (reg)); db_printf("Auxiliary Feat 0: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 4" : "=r" (reg)); db_printf("Memory Model Feat 0: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 5" : "=r" (reg)); db_printf("Memory Model Feat 1: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 6" : "=r" (reg)); db_printf("Memory Model Feat 2: 0x%08x\n", reg); __asm __volatile("mrc p15, 0, %0, c0, c1, 7" : "=r" (reg)); db_printf("Memory Model Feat 3: 0x%08x\n", reg); __asm __volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (reg)); db_printf("Aux Func Modes Ctrl 0: 0x%08x\n",reg); __asm __volatile("mrc p15, 1, %0, c15, c2, 1" : "=r" (reg)); db_printf("Aux Func Modes Ctrl 1: 0x%08x\n",reg); __asm __volatile("mrc p15, 1, %0, c15, c12, 0" : "=r" (reg)); db_printf("CPU ID code extension: 0x%08x\n",reg); } DB_SHOW_COMMAND(vtop, db_show_vtop) { u_int reg; if (have_addr) { __asm __volatile("mcr p15, 0, %0, c7, c8, 0" : : "r" (addr)); __asm __volatile("mrc p15, 0, %0, c7, c4, 0" : "=r" (reg)); db_printf("Physical address reg: 0x%08x\n",reg); } else db_printf("show vtop \n"); } #endif /* DDB */ #endif /* CPU_MV_PJ4B */ Index: projects/release-pkg/sys/arm/mv/mv_pci.c =================================================================== --- projects/release-pkg/sys/arm/mv/mv_pci.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/mv_pci.c (revision 294448) @@ -1,1197 +1,1216 @@ /*- * Copyright (c) 2008 MARVELL INTERNATIONAL LTD. * Copyright (c) 2010 The FreeBSD Foundation - * Copyright (c) 2010-2012 Semihalf + * Copyright (c) 2010-2015 Semihalf * All rights reserved. * * Developed by Semihalf. * * Portions of this software were developed by Semihalf * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Marvell integrated PCI/PCI-Express controller driver. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ofw_bus_if.h" #include "pcib_if.h" #include #include #include #include #include #include #ifdef DEBUG #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif /* * Code and data related to fdt-based PCI configuration. * * This stuff used to be in dev/fdt/fdt_pci.c and fdt_common.h, but it was * always Marvell-specific so that was deleted and the code now lives here. */ struct mv_pci_range { u_long base_pci; u_long base_parent; u_long len; }; #define FDT_RANGES_CELLS ((3 + 3 + 2) * 2) static void mv_pci_range_dump(struct mv_pci_range *range) { #ifdef DEBUG printf("\n"); printf(" base_pci = 0x%08lx\n", range->base_pci); printf(" base_par = 0x%08lx\n", range->base_parent); printf(" len = 0x%08lx\n", range->len); #endif } static int mv_pci_ranges_decode(phandle_t node, struct mv_pci_range *io_space, struct mv_pci_range *mem_space) { pcell_t ranges[FDT_RANGES_CELLS]; struct mv_pci_range *pci_space; pcell_t addr_cells, size_cells, par_addr_cells; pcell_t *rangesptr; pcell_t cell0, cell1, cell2; int tuple_size, tuples, i, rv, offset_cells, len; /* * Retrieve 'ranges' property. */ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) return (EINVAL); if (addr_cells != 3 || size_cells != 2) return (ERANGE); par_addr_cells = fdt_parent_addr_cells(node); if (par_addr_cells > 3) return (ERANGE); len = OF_getproplen(node, "ranges"); if (len > sizeof(ranges)) return (ENOMEM); if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) return (EINVAL); tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + size_cells); tuples = len / tuple_size; /* * Initialize the ranges so that we don't have to worry about * having them all defined in the FDT. In particular, it is * perfectly fine not to want I/O space on PCI busses. */ bzero(io_space, sizeof(*io_space)); bzero(mem_space, sizeof(*mem_space)); rangesptr = &ranges[0]; offset_cells = 0; for (i = 0; i < tuples; i++) { cell0 = fdt_data_get((void *)rangesptr, 1); rangesptr++; cell1 = fdt_data_get((void *)rangesptr, 1); rangesptr++; cell2 = fdt_data_get((void *)rangesptr, 1); rangesptr++; if (cell0 & 0x02000000) { pci_space = mem_space; } else if (cell0 & 0x01000000) { pci_space = io_space; } else { rv = ERANGE; goto out; } if (par_addr_cells == 3) { /* * This is a PCI subnode 'ranges'. Skip cell0 and * cell1 of this entry and only use cell2. */ offset_cells = 2; rangesptr += offset_cells; } if ((par_addr_cells - offset_cells) > 2) { rv = ERANGE; goto out; } pci_space->base_parent = fdt_data_get((void *)rangesptr, par_addr_cells - offset_cells); rangesptr += par_addr_cells - offset_cells; if (size_cells > 2) { rv = ERANGE; goto out; } pci_space->len = fdt_data_get((void *)rangesptr, size_cells); rangesptr += size_cells; pci_space->base_pci = cell2; } rv = 0; out: return (rv); } static int mv_pci_ranges(phandle_t node, struct mv_pci_range *io_space, struct mv_pci_range *mem_space) { int err; debugf("Processing PCI node: %x\n", node); if ((err = mv_pci_ranges_decode(node, io_space, mem_space)) != 0) { debugf("could not decode parent PCI node 'ranges'\n"); return (err); } debugf("Post fixup dump:\n"); mv_pci_range_dump(io_space); mv_pci_range_dump(mem_space); return (0); } int mv_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_va, vm_offset_t mem_va) { struct mv_pci_range io_space, mem_space; int error; if ((error = mv_pci_ranges_decode(node, &io_space, &mem_space)) != 0) return (error); devmap->pd_va = (io_va ? io_va : io_space.base_parent); devmap->pd_pa = io_space.base_parent; devmap->pd_size = io_space.len; devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE; devmap->pd_cache = PTE_DEVICE; devmap++; devmap->pd_va = (mem_va ? mem_va : mem_space.base_parent); devmap->pd_pa = mem_space.base_parent; devmap->pd_size = mem_space.len; devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE; devmap->pd_cache = PTE_DEVICE; return (0); } /* * Code and data related to the Marvell pcib driver. */ #define PCI_CFG_ENA (1U << 31) #define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) #define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) #define PCI_CFG_FUN(fun) (((fun) & 0x7) << 8) #define PCI_CFG_PCIE_REG(reg) ((reg) & 0xfc) #define PCI_REG_CFG_ADDR 0x0C78 #define PCI_REG_CFG_DATA 0x0C7C #define PCIE_REG_CFG_ADDR 0x18F8 #define PCIE_REG_CFG_DATA 0x18FC #define PCIE_REG_CONTROL 0x1A00 #define PCIE_CTRL_LINK1X 0x00000001 #define PCIE_REG_STATUS 0x1A04 #define PCIE_REG_IRQ_MASK 0x1910 #define PCIE_CONTROL_ROOT_CMPLX (1 << 1) #define PCIE_CONTROL_HOT_RESET (1 << 24) #define PCIE_LINK_TIMEOUT 1000000 #define PCIE_STATUS_LINK_DOWN 1 #define PCIE_STATUS_DEV_OFFS 16 /* Minimum PCI Memory and I/O allocations taken from PCI spec (in bytes) */ #define PCI_MIN_IO_ALLOC 4 #define PCI_MIN_MEM_ALLOC 16 #define BITS_PER_UINT32 (NBBY * sizeof(uint32_t)) struct mv_pcib_softc { device_t sc_dev; struct rman sc_mem_rman; bus_addr_t sc_mem_base; bus_addr_t sc_mem_size; uint32_t sc_mem_map[MV_PCI_MEM_SLICE_SIZE / (PCI_MIN_MEM_ALLOC * BITS_PER_UINT32)]; int sc_win_target; int sc_mem_win_attr; struct rman sc_io_rman; bus_addr_t sc_io_base; bus_addr_t sc_io_size; uint32_t sc_io_map[MV_PCI_IO_SLICE_SIZE / (PCI_MIN_IO_ALLOC * BITS_PER_UINT32)]; int sc_io_win_attr; struct resource *sc_res; bus_space_handle_t sc_bsh; bus_space_tag_t sc_bst; int sc_rid; struct mtx sc_msi_mtx; uint32_t sc_msi_bitmap; int sc_busnr; /* Host bridge bus number */ int sc_devnr; /* Host bridge device number */ int sc_type; int sc_mode; /* Endpoint / Root Complex */ struct ofw_bus_iinfo sc_pci_iinfo; }; /* Local forward prototypes */ static int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *); static void mv_pcib_hw_cfginit(void); static uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int, u_int, u_int, int); static void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int, u_int, u_int, uint32_t, int); static int mv_pcib_init(struct mv_pcib_softc *, int, int); static int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int); static void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int); static inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t); static void mv_pcib_enable(struct mv_pcib_softc *, uint32_t); static int mv_pcib_mem_init(struct mv_pcib_softc *); /* Forward prototypes */ static int mv_pcib_probe(device_t); static int mv_pcib_attach(device_t); static struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static int mv_pcib_release_resource(device_t, device_t, int, int, struct resource *); static int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *); static int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t); static int mv_pcib_maxslots(device_t); static uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int); static void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int mv_pcib_route_interrupt(device_t, device_t, int); #if defined(SOC_MV_ARMADAXP) static int mv_pcib_alloc_msi(device_t, device_t, int, int, int *); static int mv_pcib_map_msi(device_t, device_t, int, uint64_t *, uint32_t *); static int mv_pcib_release_msi(device_t, device_t, int, int *); #endif /* * Bus interface definitions. */ static device_method_t mv_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mv_pcib_probe), DEVMETHOD(device_attach, mv_pcib_attach), /* Bus interface */ DEVMETHOD(bus_read_ivar, mv_pcib_read_ivar), DEVMETHOD(bus_write_ivar, mv_pcib_write_ivar), DEVMETHOD(bus_alloc_resource, mv_pcib_alloc_resource), DEVMETHOD(bus_release_resource, mv_pcib_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, mv_pcib_maxslots), DEVMETHOD(pcib_read_config, mv_pcib_read_config), DEVMETHOD(pcib_write_config, mv_pcib_write_config), DEVMETHOD(pcib_route_interrupt, mv_pcib_route_interrupt), #if defined(SOC_MV_ARMADAXP) DEVMETHOD(pcib_alloc_msi, mv_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, mv_pcib_release_msi), DEVMETHOD(pcib_map_msi, mv_pcib_map_msi), #endif /* OFW bus interface */ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; static driver_t mv_pcib_driver = { "pcib", mv_pcib_methods, sizeof(struct mv_pcib_softc), }; devclass_t pcib_devclass; DRIVER_MODULE(pcib, ofwbus, mv_pcib_driver, pcib_devclass, 0, 0); static struct mtx pcicfg_mtx; static int mv_pcib_probe(device_t self) { phandle_t node; node = ofw_bus_get_node(self); if (!fdt_is_type(node, "pci")) return (ENXIO); if (!(ofw_bus_is_compatible(self, "mrvl,pcie") || ofw_bus_is_compatible(self, "mrvl,pci"))) return (ENXIO); device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller"); return (BUS_PROBE_DEFAULT); } static int mv_pcib_attach(device_t self) { struct mv_pcib_softc *sc; phandle_t node, parnode; uint32_t val, unit; int err; sc = device_get_softc(self); sc->sc_dev = self; unit = fdt_get_unit(self); node = ofw_bus_get_node(self); parnode = OF_parent(node); if (fdt_is_compatible(node, "mrvl,pcie")) { sc->sc_type = MV_TYPE_PCIE; sc->sc_win_target = MV_WIN_PCIE_TARGET(unit); sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(unit); sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(unit); } else if (fdt_is_compatible(node, "mrvl,pci")) { sc->sc_type = MV_TYPE_PCI; sc->sc_win_target = MV_WIN_PCI_TARGET; sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR; sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR; } else return (ENXIO); /* * Retrieve our mem-mapped registers range. */ sc->sc_rid = 0; sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid, RF_ACTIVE); if (sc->sc_res == NULL) { device_printf(self, "could not map memory\n"); return (ENXIO); } sc->sc_bst = rman_get_bustag(sc->sc_res); sc->sc_bsh = rman_get_bushandle(sc->sc_res); val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_CONTROL); sc->sc_mode = (val & PCIE_CONTROL_ROOT_CMPLX ? MV_MODE_ROOT : MV_MODE_ENDPOINT); /* * Get PCI interrupt info. */ if (sc->sc_mode == MV_MODE_ROOT) ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(pcell_t)); /* * Configure decode windows for PCI(E) access. */ if (mv_pcib_decode_win(node, sc) != 0) return (ENXIO); mv_pcib_hw_cfginit(); /* * Enable PCIE device. */ mv_pcib_enable(sc, unit); /* * Memory management. */ err = mv_pcib_mem_init(sc); if (err) return (err); if (sc->sc_mode == MV_MODE_ROOT) { err = mv_pcib_init(sc, sc->sc_busnr, mv_pcib_maxslots(sc->sc_dev)); if (err) goto error; device_add_child(self, "pci", -1); } else { sc->sc_devnr = 1; bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS, 1 << PCIE_STATUS_DEV_OFFS); device_add_child(self, "pci_ep", -1); } mtx_init(&sc->sc_msi_mtx, "msi_mtx", NULL, MTX_DEF); return (bus_generic_attach(self)); error: /* XXX SYS_RES_ should be released here */ rman_fini(&sc->sc_mem_rman); rman_fini(&sc->sc_io_rman); return (err); } static void mv_pcib_enable(struct mv_pcib_softc *sc, uint32_t unit) { uint32_t val; #if !defined(SOC_MV_ARMADAXP) int timeout; /* * Check if PCIE device is enabled. */ if (read_cpu_ctrl(CPU_CONTROL) & CPU_CONTROL_PCIE_DISABLE(unit)) { write_cpu_ctrl(CPU_CONTROL, read_cpu_ctrl(CPU_CONTROL) & ~(CPU_CONTROL_PCIE_DISABLE(unit))); timeout = PCIE_LINK_TIMEOUT; val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS); while (((val & PCIE_STATUS_LINK_DOWN) == 1) && (timeout > 0)) { DELAY(1000); timeout -= 1000; val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS); } } #endif if (sc->sc_mode == MV_MODE_ROOT) { /* * Enable PCI bridge. */ val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND); val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND, val); } } static int mv_pcib_mem_init(struct mv_pcib_softc *sc) { int err; /* * Memory management. */ sc->sc_mem_rman.rm_type = RMAN_ARRAY; err = rman_init(&sc->sc_mem_rman); if (err) return (err); sc->sc_io_rman.rm_type = RMAN_ARRAY; err = rman_init(&sc->sc_io_rman); if (err) { rman_fini(&sc->sc_mem_rman); return (err); } err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base, sc->sc_mem_base + sc->sc_mem_size - 1); if (err) goto error; err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base, sc->sc_io_base + sc->sc_io_size - 1); if (err) goto error; return (0); error: rman_fini(&sc->sc_mem_rman); rman_fini(&sc->sc_io_rman); return (err); } static inline uint32_t pcib_bit_get(uint32_t *map, uint32_t bit) { uint32_t n = bit / BITS_PER_UINT32; bit = bit % BITS_PER_UINT32; return (map[n] & (1 << bit)); } static inline void pcib_bit_set(uint32_t *map, uint32_t bit) { uint32_t n = bit / BITS_PER_UINT32; bit = bit % BITS_PER_UINT32; map[n] |= (1 << bit); } static inline uint32_t pcib_map_check(uint32_t *map, uint32_t start, uint32_t bits) { uint32_t i; for (i = start; i < start + bits; i++) if (pcib_bit_get(map, i)) return (0); return (1); } static inline void pcib_map_set(uint32_t *map, uint32_t start, uint32_t bits) { uint32_t i; for (i = start; i < start + bits; i++) pcib_bit_set(map, i); } /* * The idea of this allocator is taken from ARM No-Cache memory * management code (sys/arm/arm/vm_machdep.c). */ static bus_addr_t pcib_alloc(struct mv_pcib_softc *sc, uint32_t smask) { uint32_t bits, bits_limit, i, *map, min_alloc, size; bus_addr_t addr = 0; bus_addr_t base; if (smask & 1) { base = sc->sc_io_base; min_alloc = PCI_MIN_IO_ALLOC; bits_limit = sc->sc_io_size / min_alloc; map = sc->sc_io_map; smask &= ~0x3; } else { base = sc->sc_mem_base; min_alloc = PCI_MIN_MEM_ALLOC; bits_limit = sc->sc_mem_size / min_alloc; map = sc->sc_mem_map; smask &= ~0xF; } size = ~smask + 1; bits = size / min_alloc; for (i = 0; i + bits <= bits_limit; i += bits) if (pcib_map_check(map, i, bits)) { pcib_map_set(map, i, bits); addr = base + (i * min_alloc); return (addr); } return (addr); } static int mv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func, int barno) { uint32_t addr, bar; int reg, width; reg = PCIR_BAR(barno); /* * Need to init the BAR register with 0xffffffff before correct * value can be read. */ mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4); bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4); if (bar == 0) return (1); /* Calculate BAR size: 64 or 32 bit (in 32-bit units) */ width = ((bar & 7) == 4) ? 2 : 1; addr = pcib_alloc(sc, bar); if (!addr) return (-1); if (bootverbose) printf("PCI %u:%u:%u: reg %x: smask=%08x: addr=%08x\n", bus, slot, func, reg, bar, addr); mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); if (width == 2) mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4, 0, 4); return (width); } static void mv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func) { bus_addr_t io_base, mem_base; uint32_t io_limit, mem_limit; int secbus; io_base = sc->sc_io_base; io_limit = io_base + sc->sc_io_size - 1; mem_base = sc->sc_mem_base; mem_limit = mem_base + sc->sc_mem_size - 1; /* Configure I/O decode registers */ mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1, io_base >> 8, 1); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1, io_base >> 16, 2); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1, io_limit >> 8, 1); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1, io_limit >> 16, 2); /* Configure memory decode registers */ mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1, mem_base >> 16, 2); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1, mem_limit >> 16, 2); /* Disable memory prefetch decode */ mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1, 0x10, 2); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1, 0x0, 4); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1, 0xF, 2); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1, 0x0, 4); secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func, PCIR_SECBUS_1, 1); /* Configure buses behind the bridge */ mv_pcib_init(sc, secbus, PCI_SLOTMAX); } static int mv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot) { int slot, func, maxfunc, error; uint8_t hdrtype, command, class, subclass; for (slot = 0; slot <= maxslot; slot++) { maxfunc = 0; for (func = 0; func <= maxfunc; func++) { hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot, func, PCIR_HDRTYPE, 1); if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; if (func == 0 && (hdrtype & PCIM_MFDEV)) maxfunc = PCI_FUNCMAX; command = mv_pcib_read_config(sc->sc_dev, bus, slot, func, PCIR_COMMAND, 1); command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_COMMAND, command, 1); error = mv_pcib_init_all_bars(sc, bus, slot, func, hdrtype); if (error) return (error); command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_COMMAND, command, 1); /* Handle PCI-PCI bridges */ class = mv_pcib_read_config(sc->sc_dev, bus, slot, func, PCIR_CLASS, 1); subclass = mv_pcib_read_config(sc->sc_dev, bus, slot, func, PCIR_SUBCLASS, 1); if (class != PCIC_BRIDGE || subclass != PCIS_BRIDGE_PCI) continue; mv_pcib_init_bridge(sc, bus, slot, func); } } /* Enable all ABCD interrupts */ pcib_write_irq_mask(sc, (0xF << 24)); return (0); } static int mv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot, int func, int hdrtype) { int maxbar, bar, i; maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6; bar = 0; /* Program the base address registers */ while (bar < maxbar) { i = mv_pcib_init_bar(sc, bus, slot, func, bar); bar += i; if (i < 0) { device_printf(sc->sc_dev, "PCI IO/Memory space exhausted\n"); return (ENOMEM); } } return (0); } static struct resource * mv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct mv_pcib_softc *sc = device_get_softc(dev); struct rman *rm = NULL; struct resource *res; switch (type) { case SYS_RES_IOPORT: rm = &sc->sc_io_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; break; default: return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid, start, end, count, flags)); }; if ((start == 0UL) && (end == ~0UL)) { start = sc->sc_mem_base; end = sc->sc_mem_base + sc->sc_mem_size - 1; count = sc->sc_mem_size; } if ((start < sc->sc_mem_base) || (start + count - 1 != end) || (end > sc->sc_mem_base + sc->sc_mem_size - 1)) return (NULL); res = rman_reserve_resource(rm, start, end, count, flags, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); rman_set_bustag(res, fdtbus_bs_tag); rman_set_bushandle(res, start); if (flags & RF_ACTIVE) if (bus_activate_resource(child, type, *rid, res)) { rman_release_resource(res); return (NULL); } return (res); } static int mv_pcib_release_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, res)); return (rman_release_resource(res)); } static int mv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct mv_pcib_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: *result = sc->sc_busnr; return (0); case PCIB_IVAR_DOMAIN: *result = device_get_unit(dev); return (0); } return (ENOENT); } static int mv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) { struct mv_pcib_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busnr = value; return (0); } return (ENOENT); } static inline void pcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask) { if (!sc->sc_type != MV_TYPE_PCI) return; bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask); } static void mv_pcib_hw_cfginit(void) { static int opened = 0; if (opened) return; mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); opened = 1; } static uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { uint32_t addr, data, ca, cd; ca = (sc->sc_type != MV_TYPE_PCI) ? PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; cd = (sc->sc_type != MV_TYPE_PCI) ? PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); mtx_lock_spin(&pcicfg_mtx); bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); data = ~0; switch (bytes) { case 1: data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, cd + (reg & 3)); break; case 2: data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh, cd + (reg & 2))); break; case 4: data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, cd)); break; } mtx_unlock_spin(&pcicfg_mtx); return (data); } static void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { uint32_t addr, ca, cd; ca = (sc->sc_type != MV_TYPE_PCI) ? PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; cd = (sc->sc_type != MV_TYPE_PCI) ? PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); mtx_lock_spin(&pcicfg_mtx); bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); switch (bytes) { case 1: bus_space_write_1(sc->sc_bst, sc->sc_bsh, cd + (reg & 3), data); break; case 2: bus_space_write_2(sc->sc_bst, sc->sc_bsh, cd + (reg & 2), htole16(data)); break; case 4: bus_space_write_4(sc->sc_bst, sc->sc_bsh, cd, htole32(data)); break; } mtx_unlock_spin(&pcicfg_mtx); } static int mv_pcib_maxslots(device_t dev) { struct mv_pcib_softc *sc = device_get_softc(dev); return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX); } +static int +mv_pcib_root_slot(device_t dev, u_int bus, u_int slot, u_int func) +{ +#if defined(SOC_MV_ARMADA38X) + struct mv_pcib_softc *sc = device_get_softc(dev); + uint32_t vendor, device; + + vendor = mv_pcib_hw_cfgread(sc, bus, slot, func, PCIR_VENDOR, + PCIR_VENDOR_LENGTH); + device = mv_pcib_hw_cfgread(sc, bus, slot, func, PCIR_DEVICE, + PCIR_DEVICE_LENGTH) & MV_DEV_FAMILY_MASK; + + return (vendor == PCI_VENDORID_MRVL && device == MV_DEV_ARMADA38X); +#else + /* On platforms other than Armada38x, root link is always at slot 0 */ + return (slot == 0); +#endif +} + static uint32_t mv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct mv_pcib_softc *sc = device_get_softc(dev); /* Return ~0 if link is inactive or trying to read from Root */ if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) & - PCIE_STATUS_LINK_DOWN) || (slot == 0)) + PCIE_STATUS_LINK_DOWN) || mv_pcib_root_slot(dev, bus, slot, func)) return (~0U); return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes)); } static void mv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { struct mv_pcib_softc *sc = device_get_softc(dev); /* Return if link is inactive or trying to write to Root */ if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) & - PCIE_STATUS_LINK_DOWN) || (slot == 0)) + PCIE_STATUS_LINK_DOWN) || mv_pcib_root_slot(dev, bus, slot, func)) return; mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes); } static int mv_pcib_route_interrupt(device_t bus, device_t dev, int pin) { struct mv_pcib_softc *sc; struct ofw_pci_register reg; uint32_t pintr, mintr[4]; int icells; phandle_t iparent; sc = device_get_softc(bus); pintr = pin; /* Fabricate imap information in case this isn't an OFW device */ bzero(®, sizeof(reg)); reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); icells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr), &iparent); if (icells > 0) return (ofw_bus_map_intr(dev, iparent, icells, mintr)); /* Maybe it's a real interrupt, not an intpin */ if (pin > 4) return (pin); device_printf(bus, "could not route pin %d for device %d.%d\n", pin, pci_get_slot(dev), pci_get_function(dev)); return (PCI_INVALID_IRQ); } static int mv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc) { struct mv_pci_range io_space, mem_space; device_t dev; int error; dev = sc->sc_dev; if ((error = mv_pci_ranges(node, &io_space, &mem_space)) != 0) { device_printf(dev, "could not retrieve 'ranges' data\n"); return (error); } /* Configure CPU decoding windows */ error = decode_win_cpu_set(sc->sc_win_target, sc->sc_io_win_attr, io_space.base_parent, io_space.len, ~0); if (error < 0) { device_printf(dev, "could not set up CPU decode " "window for PCI IO\n"); return (ENXIO); } error = decode_win_cpu_set(sc->sc_win_target, sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len, mem_space.base_parent); if (error < 0) { device_printf(dev, "could not set up CPU decode " "windows for PCI MEM\n"); return (ENXIO); } sc->sc_io_base = io_space.base_parent; sc->sc_io_size = io_space.len; sc->sc_mem_base = mem_space.base_parent; sc->sc_mem_size = mem_space.len; return (0); } #if defined(SOC_MV_ARMADAXP) static int mv_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, uint32_t *data) { struct mv_pcib_softc *sc; sc = device_get_softc(dev); irq = irq - MSI_IRQ; /* validate parameters */ if (isclr(&sc->sc_msi_bitmap, irq)) { device_printf(dev, "invalid MSI 0x%x\n", irq); return (EINVAL); } mv_msi_data(irq, addr, data); debugf("%s: irq: %d addr: %jx data: %x\n", __func__, irq, *addr, *data); return (0); } static int mv_pcib_alloc_msi(device_t dev, device_t child, int count, int maxcount __unused, int *irqs) { struct mv_pcib_softc *sc; u_int start = 0, i; if (powerof2(count) == 0 || count > MSI_IRQ_NUM) return (EINVAL); sc = device_get_softc(dev); mtx_lock(&sc->sc_msi_mtx); for (start = 0; (start + count) < MSI_IRQ_NUM; start++) { for (i = start; i < start + count; i++) { if (isset(&sc->sc_msi_bitmap, i)) break; } if (i == start + count) break; } if ((start + count) == MSI_IRQ_NUM) { mtx_unlock(&sc->sc_msi_mtx); return (ENXIO); } for (i = start; i < start + count; i++) { setbit(&sc->sc_msi_bitmap, i); *irqs++ = MSI_IRQ + i; } debugf("%s: start: %x count: %x\n", __func__, start, count); mtx_unlock(&sc->sc_msi_mtx); return (0); } static int mv_pcib_release_msi(device_t dev, device_t child, int count, int *irqs) { struct mv_pcib_softc *sc; u_int i; sc = device_get_softc(dev); mtx_lock(&sc->sc_msi_mtx); for (i = 0; i < count; i++) clrbit(&sc->sc_msi_bitmap, irqs[i] - MSI_IRQ); mtx_unlock(&sc->sc_msi_mtx); return (0); } #endif Index: projects/release-pkg/sys/arm/mv/mvreg.h =================================================================== --- projects/release-pkg/sys/arm/mv/mvreg.h (revision 294447) +++ projects/release-pkg/sys/arm/mv/mvreg.h (revision 294448) @@ -1,447 +1,493 @@ /*- * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MVREG_H_ #define _MVREG_H_ +#include + #if defined(SOC_MV_DISCOVERY) #define IRQ_CAUSE_ERROR 0x0 #define IRQ_CAUSE 0x4 #define IRQ_CAUSE_HI 0x8 #define IRQ_MASK_ERROR 0xC #define IRQ_MASK 0x10 #define IRQ_MASK_HI 0x14 #define IRQ_CAUSE_SELECT 0x18 #define FIQ_MASK_ERROR 0x1C #define FIQ_MASK 0x20 #define FIQ_MASK_HI 0x24 #define FIQ_CAUSE_SELECT 0x28 #define ENDPOINT_IRQ_MASK_ERROR(n) 0x2C #define ENDPOINT_IRQ_MASK(n) 0x30 #define ENDPOINT_IRQ_MASK_HI(n) 0x34 #define ENDPOINT_IRQ_CAUSE_SELECT 0x38 #elif defined (SOC_MV_LOKIPLUS) || defined (SOC_MV_FREY) #define IRQ_CAUSE 0x0 #define IRQ_MASK 0x4 #define FIQ_MASK 0x8 #define ENDPOINT_IRQ_MASK(n) (0xC + (n) * 4) #define IRQ_CAUSE_HI (-1) /* Fake defines for unified */ #define IRQ_MASK_HI (-1) /* interrupt controller code */ #define FIQ_MASK_HI (-1) #define ENDPOINT_IRQ_MASK_HI(n) (-1) #define ENDPOINT_IRQ_MASK_ERROR(n) (-1) #define IRQ_CAUSE_ERROR (-1) #define IRQ_MASK_ERROR (-1) #elif defined (SOC_MV_ARMADAXP) #define IRQ_CAUSE 0x18 #define IRQ_MASK 0x30 #else /* !SOC_MV_DISCOVERY && !SOC_MV_LOKIPLUS */ #define IRQ_CAUSE 0x0 #define IRQ_MASK 0x4 #define FIQ_MASK 0x8 #define ENDPOINT_IRQ_MASK(n) 0xC #define IRQ_CAUSE_HI 0x10 #define IRQ_MASK_HI 0x14 #define FIQ_MASK_HI 0x18 #define ENDPOINT_IRQ_MASK_HI(n) 0x1C #define ENDPOINT_IRQ_MASK_ERROR(n) (-1) #define IRQ_CAUSE_ERROR (-1) /* Fake defines for unified */ #define IRQ_MASK_ERROR (-1) /* interrupt controller code */ #endif #if defined(SOC_MV_FREY) #define BRIDGE_IRQ_CAUSE 0x118 #define IRQ_TIMER0 0x00000002 #define IRQ_TIMER1 0x00000004 #define IRQ_TIMER_WD 0x00000008 #define BRIDGE_IRQ_MASK 0x11c #define IRQ_TIMER0_MASK 0x00000002 #define IRQ_TIMER1_MASK 0x00000004 #define IRQ_TIMER_WD_MASK 0x00000008 #elif defined(SOC_MV_ARMADAXP) #define BRIDGE_IRQ_CAUSE 0x68 #define IRQ_TIMER0 0x00000001 #define IRQ_TIMER1 0x00000002 #define IRQ_TIMER_WD 0x00000004 #else #define BRIDGE_IRQ_CAUSE 0x10 #define IRQ_CPU_SELF 0x00000001 #define IRQ_TIMER0 0x00000002 #define IRQ_TIMER1 0x00000004 #define IRQ_TIMER_WD 0x00000008 #define BRIDGE_IRQ_MASK 0x14 #define IRQ_CPU_MASK 0x00000001 #define IRQ_TIMER0_MASK 0x00000002 #define IRQ_TIMER1_MASK 0x00000004 #define IRQ_TIMER_WD_MASK 0x00000008 #endif #if defined(SOC_MV_LOKIPLUS) || defined(SOC_MV_FREY) #define IRQ_CPU_SELF_CLR IRQ_CPU_SELF #define IRQ_TIMER0_CLR IRQ_TIMER0 #define IRQ_TIMER1_CLR IRQ_TIMER1 #define IRQ_TIMER_WD_CLR IRQ_TIMER_WD #else #define IRQ_CPU_SELF_CLR (~IRQ_CPU_SELF) #define IRQ_TIMER0_CLR (~IRQ_TIMER0) #define IRQ_TIMER1_CLR (~IRQ_TIMER1) #define IRQ_TIMER_WD_CLR (~IRQ_TIMER_WD) #endif /* * System reset */ -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define RSTOUTn_MASK 0x60 +#define RSTOUTn_MASK_WD 0x400 #define SYSTEM_SOFT_RESET 0x64 #define WD_RSTOUTn_MASK 0x4 #define WD_GLOBAL_MASK 0x00000100 #define WD_CPU0_MASK 0x00000001 #define SOFT_RST_OUT_EN 0x00000001 #define SYS_SOFT_RST 0x00000001 #else #define RSTOUTn_MASK 0x8 #define WD_RST_OUT_EN 0x00000002 #define SOFT_RST_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET 0xc #define SYS_SOFT_RST 0x00000001 #endif /* * Power Control */ #if defined(SOC_MV_KIRKWOOD) #define CPU_PM_CTRL 0x18 #else #define CPU_PM_CTRL 0x1C #endif #define CPU_PM_CTRL_NONE 0 #define CPU_PM_CTRL_ALL ~0x0 #if defined(SOC_MV_KIRKWOOD) #define CPU_PM_CTRL_GE0 (1 << 0) #define CPU_PM_CTRL_PEX0_PHY (1 << 1) #define CPU_PM_CTRL_PEX0 (1 << 2) #define CPU_PM_CTRL_USB0 (1 << 3) #define CPU_PM_CTRL_SDIO (1 << 4) #define CPU_PM_CTRL_TSU (1 << 5) #define CPU_PM_CTRL_DUNIT (1 << 6) #define CPU_PM_CTRL_RUNIT (1 << 7) #define CPU_PM_CTRL_XOR0 (1 << 8) #define CPU_PM_CTRL_AUDIO (1 << 9) #define CPU_PM_CTRL_SATA0 (1 << 14) #define CPU_PM_CTRL_SATA1 (1 << 15) #define CPU_PM_CTRL_XOR1 (1 << 16) #define CPU_PM_CTRL_CRYPTO (1 << 17) #define CPU_PM_CTRL_GE1 (1 << 19) #define CPU_PM_CTRL_TDM (1 << 20) #define CPU_PM_CTRL_XOR (CPU_PM_CTRL_XOR0 | CPU_PM_CTRL_XOR1) #define CPU_PM_CTRL_USB(u) (CPU_PM_CTRL_USB0) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_GE1 * (u) | CPU_PM_CTRL_GE0 * \ (1 - (u))) #define CPU_PM_CTRL_IDMA (CPU_PM_CTRL_NONE) #elif defined(SOC_MV_DISCOVERY) #define CPU_PM_CTRL_GE0 (1 << 1) #define CPU_PM_CTRL_GE1 (1 << 2) #define CPU_PM_CTRL_PEX00 (1 << 5) #define CPU_PM_CTRL_PEX01 (1 << 6) #define CPU_PM_CTRL_PEX02 (1 << 7) #define CPU_PM_CTRL_PEX03 (1 << 8) #define CPU_PM_CTRL_PEX10 (1 << 9) #define CPU_PM_CTRL_PEX11 (1 << 10) #define CPU_PM_CTRL_PEX12 (1 << 11) #define CPU_PM_CTRL_PEX13 (1 << 12) #define CPU_PM_CTRL_SATA0_PHY (1 << 13) #define CPU_PM_CTRL_SATA0 (1 << 14) #define CPU_PM_CTRL_SATA1_PHY (1 << 15) #define CPU_PM_CTRL_SATA1 (1 << 16) #define CPU_PM_CTRL_USB0 (1 << 17) #define CPU_PM_CTRL_USB1 (1 << 18) #define CPU_PM_CTRL_USB2 (1 << 19) #define CPU_PM_CTRL_IDMA (1 << 20) #define CPU_PM_CTRL_XOR (1 << 21) #define CPU_PM_CTRL_CRYPTO (1 << 22) #define CPU_PM_CTRL_DEVICE (1 << 23) #define CPU_PM_CTRL_USB(u) (1 << (17 + (u))) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_GE1 * (u) | CPU_PM_CTRL_GE0 * \ (1 - (u))) #else #define CPU_PM_CTRL_CRYPTO (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_IDMA (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_XOR (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_USB(u) (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_NONE) #endif /* * Timers */ #define CPU_TIMERS_BASE 0x300 #define CPU_TIMER_CONTROL 0x0 #define CPU_TIMER0_EN 0x00000001 #define CPU_TIMER0_AUTO 0x00000002 #define CPU_TIMER1_EN 0x00000004 #define CPU_TIMER1_AUTO 0x00000008 -#define CPU_TIMER_WD_EN 0x00000010 -#define CPU_TIMER_WD_AUTO 0x00000020 +#define CPU_TIMER2_EN 0x00000010 +#define CPU_TIMER2_AUTO 0x00000020 +#define CPU_TIMER_WD_EN 0x00000100 +#define CPU_TIMER_WD_AUTO 0x00000200 /* 25MHz mode is Armada XP - specific */ #define CPU_TIMER_WD_25MHZ_EN 0x00000400 #define CPU_TIMER0_25MHZ_EN 0x00000800 #define CPU_TIMER1_25MHZ_EN 0x00001000 #define CPU_TIMER0_REL 0x10 #define CPU_TIMER0 0x14 /* * SATA */ #define SATA_CHAN_NUM 2 #define EDMA_REGISTERS_OFFSET 0x2000 #define EDMA_REGISTERS_SIZE 0x2000 #define SATA_EDMA_BASE(ch) (EDMA_REGISTERS_OFFSET + \ ((ch) * EDMA_REGISTERS_SIZE)) /* SATAHC registers */ #define SATA_CR 0x000 /* Configuration Reg. */ #define SATA_CR_NODMABS (1 << 8) #define SATA_CR_NOEDMABS (1 << 9) #define SATA_CR_NOPRDPBS (1 << 10) #define SATA_CR_COALDIS(ch) (1 << (24 + ch)) /* Interrupt Coalescing Threshold Reg. */ #define SATA_ICTR 0x00C #define SATA_ICTR_MAX ((1 << 8) - 1) /* Interrupt Time Threshold Reg. */ #define SATA_ITTR 0x010 #define SATA_ITTR_MAX ((1 << 24) - 1) #define SATA_ICR 0x014 /* Interrupt Cause Reg. */ #define SATA_ICR_DMADONE(ch) (1 << (ch)) #define SATA_ICR_COAL (1 << 4) #define SATA_ICR_DEV(ch) (1 << (8 + ch)) #define SATA_MICR 0x020 /* Main Interrupt Cause Reg. */ #define SATA_MICR_ERR(ch) (1 << (2 * ch)) #define SATA_MICR_DONE(ch) (1 << ((2 * ch) + 1)) #define SATA_MICR_DMADONE(ch) (1 << (4 + ch)) #define SATA_MICR_COAL (1 << 8) #define SATA_MIMR 0x024 /* Main Interrupt Mask Reg. */ /* Shadow registers */ #define SATA_SHADOWR_BASE(ch) (SATA_EDMA_BASE(ch) + 0x100) #define SATA_SHADOWR_CONTROL(ch) (SATA_EDMA_BASE(ch) + 0x120) /* SATA registers */ #define SATA_SATA_SSTATUS(ch) (SATA_EDMA_BASE(ch) + 0x300) #define SATA_SATA_SERROR(ch) (SATA_EDMA_BASE(ch) + 0x304) #define SATA_SATA_SCONTROL(ch) (SATA_EDMA_BASE(ch) + 0x308) #define SATA_SATA_FISICR(ch) (SATA_EDMA_BASE(ch) + 0x364) /* EDMA registers */ #define SATA_EDMA_CFG(ch) (SATA_EDMA_BASE(ch) + 0x000) #define SATA_EDMA_CFG_QL128 (1 << 19) #define SATA_EDMA_CFG_HQCACHE (1 << 22) #define SATA_EDMA_IECR(ch) (SATA_EDMA_BASE(ch) + 0x008) #define SATA_EDMA_IEMR(ch) (SATA_EDMA_BASE(ch) + 0x00C) #define SATA_EDMA_REQBAHR(ch) (SATA_EDMA_BASE(ch) + 0x010) #define SATA_EDMA_REQIPR(ch) (SATA_EDMA_BASE(ch) + 0x014) #define SATA_EDMA_REQOPR(ch) (SATA_EDMA_BASE(ch) + 0x018) #define SATA_EDMA_RESBAHR(ch) (SATA_EDMA_BASE(ch) + 0x01C) #define SATA_EDMA_RESIPR(ch) (SATA_EDMA_BASE(ch) + 0x020) #define SATA_EDMA_RESOPR(ch) (SATA_EDMA_BASE(ch) + 0x024) #define SATA_EDMA_CMD(ch) (SATA_EDMA_BASE(ch) + 0x028) #define SATA_EDMA_CMD_ENABLE (1 << 0) #define SATA_EDMA_CMD_DISABLE (1 << 1) #define SATA_EDMA_CMD_RESET (1 << 2) #define SATA_EDMA_STATUS(ch) (SATA_EDMA_BASE(ch) + 0x030) #define SATA_EDMA_STATUS_IDLE (1 << 7) /* Offset to extract input slot from REQIPR register */ #define SATA_EDMA_REQIS_OFS 5 /* Offset to extract input slot from RESOPR register */ #define SATA_EDMA_RESOS_OFS 3 /* * GPIO */ #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_OUT_EN_CTRL 0x04 #define GPIO_BLINK_EN 0x08 #define GPIO_DATA_IN_POLAR 0x0c #define GPIO_DATA_IN 0x10 #define GPIO_INT_CAUSE 0x14 #define GPIO_INT_EDGE_MASK 0x18 #define GPIO_INT_LEV_MASK 0x1c #define GPIO_HI_DATA_OUT 0x40 #define GPIO_HI_DATA_OUT_EN_CTRL 0x44 #define GPIO_HI_BLINK_EN 0x48 #define GPIO_HI_DATA_IN_POLAR 0x4c #define GPIO_HI_DATA_IN 0x50 #define GPIO_HI_INT_CAUSE 0x54 #define GPIO_HI_INT_EDGE_MASK 0x58 #define GPIO_HI_INT_LEV_MASK 0x5c #define GPIO(n) (1 << (n)) #define MV_GPIO_MAX_NPINS 64 #define MV_GPIO_IN_NONE 0x0 #define MV_GPIO_IN_POL_LOW (1 << 16) #define MV_GPIO_IN_IRQ_EDGE (2 << 16) #define MV_GPIO_IN_IRQ_LEVEL (4 << 16) #define MV_GPIO_OUT_NONE 0x0 #define MV_GPIO_OUT_BLINK 0x1 #define MV_GPIO_OUT_OPEN_DRAIN 0x2 #define MV_GPIO_OUT_OPEN_SRC 0x4 #define IS_GPIO_IRQ(irq) ((irq) >= NIRQ && (irq) < NIRQ + MV_GPIO_MAX_NPINS) #define GPIO2IRQ(gpio) ((gpio) + NIRQ) #define IRQ2GPIO(irq) ((irq) - NIRQ) #if defined(SOC_MV_ORION) || defined(SOC_MV_LOKIPLUS) #define SAMPLE_AT_RESET 0x10 #elif defined(SOC_MV_KIRKWOOD) #define SAMPLE_AT_RESET 0x30 #elif defined(SOC_MV_FREY) #define SAMPLE_AT_RESET 0x100 +#elif defined(SOC_MV_ARMADA38X) +#define SAMPLE_AT_RESET 0x400 #endif #if defined(SOC_MV_DISCOVERY) #define SAMPLE_AT_RESET_LO 0x30 #define SAMPLE_AT_RESET_HI 0x34 #elif defined(SOC_MV_DOVE) #define SAMPLE_AT_RESET_LO 0x14 #define SAMPLE_AT_RESET_HI 0x18 #elif defined(SOC_MV_ARMADAXP) #define SAMPLE_AT_RESET_LO 0x30 #define SAMPLE_AT_RESET_HI 0x34 #endif /* * Clocks */ #if defined(SOC_MV_ORION) #define TCLK_MASK 0x00000300 #define TCLK_SHIFT 0x08 #elif defined(SOC_MV_DISCOVERY) #define TCLK_MASK 0x00000180 #define TCLK_SHIFT 0x07 #elif defined(SOC_MV_LOKIPLUS) #define TCLK_MASK 0x0000F000 #define TCLK_SHIFT 0x0C +#elif defined(SOC_MV_ARMADA38X) +#define TCLK_MASK 0x00008000 +#define TCLK_SHIFT 15 #endif #define TCLK_100MHZ 100000000 #define TCLK_125MHZ 125000000 #define TCLK_133MHZ 133333333 #define TCLK_150MHZ 150000000 #define TCLK_166MHZ 166666667 #define TCLK_200MHZ 200000000 #define TCLK_250MHZ 250000000 #define TCLK_300MHZ 300000000 #define TCLK_667MHZ 667000000 /* * CPU Cache Configuration */ #define CPU_CONFIG 0x00000000 #define CPU_CONFIG_IC_PREF 0x00010000 #define CPU_CONFIG_DC_PREF 0x00020000 #define CPU_CONTROL 0x00000004 #define CPU_CONTROL_L2_SIZE 0x00200000 /* Only on Discovery */ #define CPU_CONTROL_L2_MODE 0x00020000 /* Only on Discovery */ #define CPU_L2_CONFIG 0x00000028 /* Only on Kirkwood */ #define CPU_L2_CONFIG_MODE 0x00000010 /* Only on Kirkwood */ /* * PCI Express port control (CPU Control registers) */ #define CPU_CONTROL_PCIE_DISABLE(n) (1 << (3 * (n))) /* * Vendor ID */ #define PCI_VENDORID_MRVL 0x11AB #define PCI_VENDORID_MRVL2 0x1B4B /* * Chip ID */ #define MV_DEV_88F5181 0x5181 #define MV_DEV_88F5182 0x5182 #define MV_DEV_88F5281 0x5281 #define MV_DEV_88F6281 0x6281 #define MV_DEV_88F6282 0x6282 #define MV_DEV_88F6781 0x6781 +#define MV_DEV_88F6828 0x6828 +#define MV_DEV_88F6820 0x6820 +#define MV_DEV_88F6810 0x6810 #define MV_DEV_MV78100_Z0 0x6381 #define MV_DEV_MV78100 0x7810 #define MV_DEV_MV78130 0x7813 #define MV_DEV_MV78160 0x7816 #define MV_DEV_MV78230 0x7823 #define MV_DEV_MV78260 0x7826 #define MV_DEV_MV78460 0x7846 #define MV_DEV_88RC8180 0x8180 #define MV_DEV_88RC9480 0x9480 #define MV_DEV_88RC9580 0x9580 #define MV_DEV_FAMILY_MASK 0xff00 #define MV_DEV_DISCOVERY 0x7800 +#define MV_DEV_ARMADA38X 0x6800 /* * Doorbell register control */ #define MV_DRBL_PCIE_TO_CPU 0 #define MV_DRBL_CPU_TO_PCIE 1 #if defined(SOC_MV_FREY) #define MV_DRBL_CAUSE(d,u) (0x60 + 0x20 * (d) + 0x8 * (u)) #define MV_DRBL_MASK(d,u) (0x60 + 0x20 * (d) + 0x8 * (u) + 0x4) #define MV_DRBL_MSG(m,d,u) (0x8 * (u) + 0x20 * (d) + 0x4 * (m)) #else #define MV_DRBL_CAUSE(d,u) (0x10 * (u) + 0x8 * (d)) #define MV_DRBL_MASK(d,u) (0x10 * (u) + 0x8 * (d) + 0x4) #define MV_DRBL_MSG(m,d,u) (0x10 * (u) + 0x8 * (d) + 0x4 * (m) + 0x30) #endif + +/* + * SCU + */ +#if defined(SOC_MV_ARMADA38X) +#define MV_SCU_BASE (MV_BASE + 0xc000) +#define MV_SCU_REGS_LEN 0x100 +#define MV_SCU_REG_CTRL 0x00 +#define MV_SCU_REG_CONFIG 0x04 +#define MV_SCU_ENABLE 1 +#define SCU_CFG_REG_NCPU_MASK 0x3 +#endif + +/* + * PMSU + */ +#if defined(SOC_MV_ARMADA38X) +#define MV_PMSU_BASE (MV_BASE + 0x22000) +#define MV_PMSU_REGS_LEN 0x1000 +#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) (((cpu) * 0x100) + 0x124) +#endif + +/* + * CPU RESET + */ +#if defined(SOC_MV_ARMADA38X) +#define MV_CPU_RESET_BASE (MV_BASE + 0x20800) +#define MV_CPU_RESET_REGS_LEN 0x8 +#define CPU_RESET_OFFSET(cpu) ((cpu) * 0x8) +#define CPU_RESET_ASSERT 0x1 +#endif + #endif /* _MVREG_H_ */ Index: projects/release-pkg/sys/arm/mv/mvvar.h =================================================================== --- projects/release-pkg/sys/arm/mv/mvvar.h (revision 294447) +++ projects/release-pkg/sys/arm/mv/mvvar.h (revision 294448) @@ -1,145 +1,145 @@ /*- * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0var.h, rev 1 * * $FreeBSD$ */ #ifndef _MVVAR_H_ #define _MVVAR_H_ #include #include #include #include #include #include #define MV_TYPE_PCI 0 #define MV_TYPE_PCIE 1 #define MV_MODE_ENDPOINT 0 #define MV_MODE_ROOT 1 struct gpio_config { int gc_gpio; /* GPIO number */ uint32_t gc_flags; /* GPIO flags */ int gc_output; /* GPIO output value */ }; struct decode_win { int target; /* Mbus unit ID */ int attr; /* Attributes of the target interface */ vm_paddr_t base; /* Physical base addr */ uint32_t size; vm_paddr_t remap; }; extern const struct gpio_config mv_gpio_config[]; extern const struct decode_win *cpu_wins; extern const struct decode_win *idma_wins; extern const struct decode_win *xor_wins; extern int idma_wins_no; extern int xor_wins_no; /* Function prototypes */ int mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, void (*hand)(void *), void *arg, int pin, int flags, void **cookiep); void mv_gpio_intr_mask(int pin); void mv_gpio_intr_unmask(int pin); void mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable); uint8_t mv_gpio_in(uint32_t pin); int soc_decode_win(void); void soc_id(uint32_t *dev, uint32_t *rev); void soc_dump_decode_win(void); uint32_t soc_power_ctrl_get(uint32_t mask); void soc_power_ctrl_set(uint32_t mask); uint64_t get_sar_value(void); int decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, vm_paddr_t remap); int decode_win_overlap(int, int, const struct decode_win *); int win_cpu_can_remap(int); void decode_win_pcie_setup(u_long); void ddr_disable(int i); int ddr_is_active(int i); uint32_t ddr_base(int i); uint32_t ddr_size(int i); uint32_t ddr_attr(int i); uint32_t ddr_target(int i); uint32_t cpu_extra_feat(void); uint32_t get_tclk(void); uint32_t get_l2clk(void); uint32_t read_cpu_ctrl(uint32_t); void write_cpu_ctrl(uint32_t, uint32_t); -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) uint32_t read_cpu_mp_clocks(uint32_t reg); void write_cpu_mp_clocks(uint32_t reg, uint32_t val); uint32_t read_cpu_misc(uint32_t reg); void write_cpu_misc(uint32_t reg, uint32_t val); #endif int mv_pcib_bar_win_set(device_t dev, uint32_t base, uint32_t size, uint32_t remap, int winno, int busno); int mv_pcib_cpu_win_remap(device_t dev, uint32_t remap, uint32_t size); void mv_mask_endpoint_irq(uintptr_t nb, int unit); void mv_unmask_endpoint_irq(uintptr_t nb, int unit); int mv_drbl_get_next_irq(int dir, int unit); void mv_drbl_mask_all(int unit); void mv_drbl_mask_irq(uint32_t irq, int dir, int unit); void mv_drbl_unmask_irq(uint32_t irq, int dir, int unit); void mv_drbl_set_mask(uint32_t val, int dir, int unit); uint32_t mv_drbl_get_mask(int dir, int unit); void mv_drbl_set_cause(uint32_t val, int dir, int unit); uint32_t mv_drbl_get_cause(int dir, int unit); void mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit); uint32_t mv_drbl_get_msg(int mnr, int dir, int unit); int mv_msi_data(int irq, uint64_t *addr, uint32_t *data); struct arm_devmap_entry; int mv_pci_devmap(phandle_t, struct arm_devmap_entry *, vm_offset_t, vm_offset_t); int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *); #endif /* _MVVAR_H_ */ Index: projects/release-pkg/sys/arm/mv/mvwin.h =================================================================== --- projects/release-pkg/sys/arm/mv/mvwin.h (revision 294447) +++ projects/release-pkg/sys/arm/mv/mvwin.h (revision 294448) @@ -1,390 +1,427 @@ /*- * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MVWIN_H_ #define _MVWIN_H_ /* * Decode windows addresses. * * All decoding windows must be aligned to their size, which has to be * a power of 2. */ /* * SoC Integrated devices: 0xF1000000, 16 MB (VA == PA) */ /* SoC Regs */ #define MV_PHYS_BASE 0xF1000000 #define MV_SIZE (1024 * 1024) /* 1 MB */ /* SRAM */ #define MV_CESA_SRAM_BASE 0xF1100000 /* AXI Regs */ #ifdef SOC_MV_DOVE #define MV_AXI_PHYS_BASE 0xF1800000 #define MV_AXI_BASE MV_AXI_PHYS_BASE #define MV_AXI_SIZE (16 * 1024 * 1024) /* 16 MB */ #endif /* * External devices: 0x80000000, 1 GB (VA == PA) * Includes Device Bus, PCI and PCIE. */ #if defined(SOC_MV_ORION) #define MV_PCI_PORTS 2 /* 1x PCI + 1x PCIE */ #elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_FREY) #define MV_PCI_PORTS 1 /* 1x PCIE */ #elif defined(SOC_MV_DISCOVERY) #define MV_PCI_PORTS 8 /* 8x PCIE */ #elif defined(SOC_MV_DOVE) || defined(SOC_MV_LOKIPLUS) #define MV_PCI_PORTS 2 /* 2x PCIE */ #elif defined(SOC_MV_ARMADAXP) #define MV_PCI_PORTS 3 /* 3x PCIE */ +#elif defined(SOC_MV_ARMADA38X) +#define MV_PCI_PORTS 4 /* 4x PCIE */ #else #error "MV_PCI_PORTS not configured !" #endif /* PCI/PCIE Memory */ #define MV_PCI_MEM_PHYS_BASE 0x80000000 #define MV_PCI_MEM_SIZE (512 * 1024 * 1024) /* 512 MB */ #define MV_PCI_MEM_BASE MV_PCI_MEM_PHYS_BASE #define MV_PCI_MEM_SLICE_SIZE (MV_PCI_MEM_SIZE / MV_PCI_PORTS) #define MV_PCI_MEM_SLICE(n) (MV_PCI_MEM_BASE + ((n) * \ MV_PCI_MEM_SLICE_SIZE)) /* PCI/PCIE I/O */ #define MV_PCI_IO_PHYS_BASE 0xBF000000 #define MV_PCI_IO_SIZE (16 * 1024 * 1024) /* 16 MB */ #define MV_PCI_IO_BASE MV_PCI_IO_PHYS_BASE #define MV_PCI_IO_SLICE_SIZE (MV_PCI_IO_SIZE / MV_PCI_PORTS) #define MV_PCI_IO_SLICE(n) (MV_PCI_IO_BASE + ((n) * MV_PCI_IO_SLICE_SIZE)) #if defined(SOC_MV_FREY) #define MV_PCI_VA_MEM_BASE MV_PCI_MEM_BASE #else #define MV_PCI_VA_MEM_BASE 0 #endif #define MV_PCI_VA_IO_BASE 0 /* * Device Bus (VA == PA) */ #define MV_DEV_BOOT_BASE 0xF9300000 #define MV_DEV_BOOT_SIZE (1024 * 1024) /* 1 MB */ #define MV_DEV_CS0_BASE 0xF9400000 #define MV_DEV_CS0_SIZE (1024 * 1024) /* 1 MB */ #define MV_DEV_CS1_BASE 0xF9500000 #define MV_DEV_CS1_SIZE (32 * 1024 * 1024) /* 32 MB */ #define MV_DEV_CS2_BASE 0xFB500000 #define MV_DEV_CS2_SIZE (1024 * 1024) /* 1 MB */ /* * Integrated SoC peripherals addresses */ #define MV_BASE MV_PHYS_BASE /* VA == PA mapping */ #if defined(SOC_MV_DOVE) #define MV_DDR_CADR_BASE (MV_AXI_BASE + 0x100) #elif defined(SOC_MV_LOKIPLUS) #define MV_DDR_CADR_BASE (MV_BASE + 0xF1500) -#elif defined(SOC_MV_ARMADAXP) +#elif defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define MV_DDR_CADR_BASE (MV_BASE + 0x20180) #else #define MV_DDR_CADR_BASE (MV_BASE + 0x1500) #endif #define MV_MPP_BASE (MV_BASE + 0x10000) -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define MV_MISC_BASE (MV_BASE + 0x18200) #define MV_MBUS_BRIDGE_BASE (MV_BASE + 0x20000) #define MV_INTREGS_BASE (MV_MBUS_BRIDGE_BASE + 0x80) #define MV_MP_CLOCKS_BASE (MV_MBUS_BRIDGE_BASE + 0x700) #define MV_CPU_CONTROL_BASE (MV_MBUS_BRIDGE_BASE + 0x1800) #elif !defined(SOC_MV_FREY) #define MV_MBUS_BRIDGE_BASE (MV_BASE + 0x20000) #define MV_INTREGS_BASE (MV_MBUS_BRIDGE_BASE + 0x80) #define MV_CPU_CONTROL_BASE (MV_MBUS_BRIDGE_BASE + 0x100) #else #define MV_CPU_CONTROL_BASE (MV_BASE + 0x10000) #endif #define MV_PCI_BASE (MV_BASE + 0x30000) #define MV_PCI_SIZE 0x2000 #if defined(SOC_MV_FREY) #define MV_PCIE_BASE (MV_BASE + 0x8000) +#elif defined(SOC_MV_ARMADA38X) +#define MV_PCIE_BASE (MV_BASE + 0x80000) #else #define MV_PCIE_BASE (MV_BASE + 0x40000) #endif #define MV_PCIE_SIZE 0x2000 #define MV_PCIE00_BASE (MV_PCIE_BASE + 0x00000) #define MV_PCIE01_BASE (MV_PCIE_BASE + 0x04000) #define MV_PCIE02_BASE (MV_PCIE_BASE + 0x08000) #define MV_PCIE03_BASE (MV_PCIE_BASE + 0x0C000) #define MV_PCIE10_BASE (MV_PCIE_BASE + 0x40000) #define MV_PCIE11_BASE (MV_PCIE_BASE + 0x44000) #define MV_PCIE12_BASE (MV_PCIE_BASE + 0x48000) #define MV_PCIE13_BASE (MV_PCIE_BASE + 0x4C000) #define MV_SDIO_BASE (MV_BASE + 0x90000) #define MV_SDIO_SIZE 0x10000 /* * Decode windows definitions and macros */ -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define MV_WIN_CPU_CTRL(n) (((n) < 8) ? 0x10 * (n) : 0x90 + (0x8 * ((n) - 8))) #define MV_WIN_CPU_BASE(n) ((((n) < 8) ? 0x10 * (n) : 0x90 + (0x8 * ((n) - 8))) + 0x4) #define MV_WIN_CPU_REMAP_LO(n) (0x10 * (n) + 0x008) #define MV_WIN_CPU_REMAP_HI(n) (0x10 * (n) + 0x00C) #else #define MV_WIN_CPU_CTRL(n) (0x10 * (n) + (((n) < 8) ? 0x000 : 0x880)) #define MV_WIN_CPU_BASE(n) (0x10 * (n) + (((n) < 8) ? 0x004 : 0x884)) #define MV_WIN_CPU_REMAP_LO(n) (0x10 * (n) + (((n) < 8) ? 0x008 : 0x888)) #define MV_WIN_CPU_REMAP_HI(n) (0x10 * (n) + (((n) < 8) ? 0x00C : 0x88C)) #endif #if defined(SOC_MV_DISCOVERY) #define MV_WIN_CPU_MAX 14 -#elif defined(SOC_MV_ARMADAXP) +#elif defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define MV_WIN_CPU_MAX 20 #else #define MV_WIN_CPU_MAX 8 #endif #define MV_WIN_CPU_ATTR_SHIFT 8 #if defined(SOC_MV_LOKIPLUS) #define MV_WIN_CPU_TARGET_SHIFT 0 #define MV_WIN_CPU_ENABLE_BIT (1 << 5) #else #define MV_WIN_CPU_TARGET_SHIFT 4 #define MV_WIN_CPU_ENABLE_BIT 1 #endif #if defined(SOC_MV_DOVE) #define MV_WIN_DDR_MAX 2 #else /* SOC_MV_DOVE */ #if defined(SOC_MV_LOKIPLUS) #define MV_WIN_DDR_BASE(n) (0xc * (n) + 0x4) #define MV_WIN_DDR_SIZE(n) (0xc * (n) + 0x0) #else /* SOC_MV_LOKIPLUS */ #define MV_WIN_DDR_BASE(n) (0x8 * (n) + 0x0) #define MV_WIN_DDR_SIZE(n) (0x8 * (n) + 0x4) #endif /* SOC_MV_LOKIPLUS */ #define MV_WIN_DDR_MAX 4 #endif /* SOC_MV_DOVE */ /* * These values are valid only for peripherals decoding windows * Bit in ATTR is zeroed according to CS bank number */ #define MV_WIN_DDR_ATTR(cs) (0x0F & ~(0x01 << (cs))) #define MV_WIN_DDR_TARGET 0x0 #if defined(SOC_MV_DISCOVERY) #define MV_WIN_CESA_TARGET 9 #define MV_WIN_CESA_ATTR(eng_sel) 1 #elif defined(SOC_MV_ARMADAXP) #define MV_WIN_CESA_TARGET 9 /* * Bits [2:3] of cesa attribute select engine: * eng_sel: * 1: engine1 * 2: engine0 */ #define MV_WIN_CESA_ATTR(eng_sel) (1 | ((eng_sel) << 2)) #else #define MV_WIN_CESA_TARGET 3 #define MV_WIN_CESA_ATTR(eng_sel) 0 #endif #define MV_WIN_USB_CTRL(n) (0x10 * (n) + 0x320) #define MV_WIN_USB_BASE(n) (0x10 * (n) + 0x324) #define MV_WIN_USB_MAX 4 #define MV_WIN_ETH_BASE(n) (0x8 * (n) + 0x200) #define MV_WIN_ETH_SIZE(n) (0x8 * (n) + 0x204) #define MV_WIN_ETH_REMAP(n) (0x4 * (n) + 0x280) #define MV_WIN_ETH_MAX 6 #define MV_WIN_IDMA_BASE(n) (0x8 * (n) + 0xa00) #define MV_WIN_IDMA_SIZE(n) (0x8 * (n) + 0xa04) #define MV_WIN_IDMA_REMAP(n) (0x4 * (n) + 0xa60) #define MV_WIN_IDMA_CAP(n) (0x4 * (n) + 0xa70) #define MV_WIN_IDMA_MAX 8 #define MV_IDMA_CHAN_MAX 4 #define MV_WIN_XOR_BASE(n, m) (0x4 * (n) + 0xa50 + (m) * 0x100) #define MV_WIN_XOR_SIZE(n, m) (0x4 * (n) + 0xa70 + (m) * 0x100) #define MV_WIN_XOR_REMAP(n, m) (0x4 * (n) + 0xa90 + (m) * 0x100) #define MV_WIN_XOR_CTRL(n, m) (0x4 * (n) + 0xa40 + (m) * 0x100) #define MV_WIN_XOR_OVERR(n, m) (0x4 * (n) + 0xaa0 + (m) * 0x100) #define MV_WIN_XOR_MAX 8 #define MV_XOR_CHAN_MAX 2 #define MV_XOR_NON_REMAP 4 #if defined(SOC_MV_DISCOVERY) || defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DOVE) #define MV_WIN_PCIE_TARGET(n) 4 #define MV_WIN_PCIE_MEM_ATTR(n) 0xE8 #define MV_WIN_PCIE_IO_ATTR(n) 0xE0 #elif defined(SOC_MV_ARMADAXP) #define MV_WIN_PCIE_TARGET(n) (4 + (4 * ((n) % 2))) #define MV_WIN_PCIE_MEM_ATTR(n) (0xE8 + (0x10 * ((n) / 2))) #define MV_WIN_PCIE_IO_ATTR(n) (0xE0 + (0x10 * ((n) / 2))) +#elif defined(SOC_MV_ARMADA38X) +#define MV_WIN_PCIE_TARGET(n) ((n) == 0 ? 8 : 4) +#define MV_WIN_PCIE_MEM_ATTR(n) ((n) < 2 ? 0xE8 : (0xD8 - (((n) % 2) * 0x20))) +#define MV_WIN_PCIE_IO_ATTR(n) ((n) < 2 ? 0xE0 : (0xD0 - (((n) % 2) * 0x20))) #elif defined(SOC_MV_ORION) #define MV_WIN_PCIE_TARGET(n) 4 #define MV_WIN_PCIE_MEM_ATTR(n) 0x59 #define MV_WIN_PCIE_IO_ATTR(n) 0x51 #elif defined(SOC_MV_LOKIPLUS) #define MV_WIN_PCIE_TARGET(n) (3 + (n)) #define MV_WIN_PCIE_MEM_ATTR(n) 0x59 #define MV_WIN_PCIE_IO_ATTR(n) 0x51 #endif #define MV_WIN_PCI_TARGET 3 #define MV_WIN_PCI_MEM_ATTR 0x59 #define MV_WIN_PCI_IO_ATTR 0x51 #define MV_WIN_PCIE_CTRL(n) (0x10 * (((n) < 5) ? (n) : \ (n) + 1) + 0x1820) #define MV_WIN_PCIE_BASE(n) (0x10 * (((n) < 5) ? (n) : \ (n) + 1) + 0x1824) #define MV_WIN_PCIE_REMAP(n) (0x10 * (((n) < 5) ? (n) : \ (n) + 1) + 0x182C) #define MV_WIN_PCIE_MAX 6 #define MV_PCIE_BAR_CTRL(n) (0x04 * (n) + 0x1800) #define MV_PCIE_BAR_BASE(n) (0x08 * ((n) < 3 ? (n) : 4) + 0x0010) #define MV_PCIE_BAR_BASE_H(n) (0x08 * (n) + 0x0014) #define MV_PCIE_BAR_MAX 4 #define MV_PCIE_BAR_64BIT (0x4) #define MV_PCIE_BAR_PREFETCH_EN (0x8) #define MV_PCIE_CONTROL (0x1a00) #define MV_PCIE_ROOT_CMPLX (1 << 1) #define MV_WIN_SATA_CTRL(n) (0x10 * (n) + 0x30) #define MV_WIN_SATA_BASE(n) (0x10 * (n) + 0x34) #define MV_WIN_SATA_MAX 4 + +#if defined(SOC_MV_ARMADA38X) +#define MV_BOOTROM_MEM_ADDR 0xFFF00000 +#define MV_BOOTROM_WIN_SIZE 0xF +#define MV_CPU_SUBSYS_REGS_LEN 0x100 + +/* IO Window Control Register fields */ +#define IO_WIN_SIZE_SHIFT 16 +#define IO_WIN_SIZE_MASK 0xFFFF +#define IO_WIN_ATTR_SHIFT 8 +#define IO_WIN_ATTR_MASK 0xFF +#define IO_WIN_TGT_SHIFT 4 +#define IO_WIN_TGT_MASK 0xF +#define IO_WIN_SYNC_SHIFT 1 +#define IO_WIN_SYNC_MASK 0x1 +#define IO_WIN_ENA_SHIFT 0 +#define IO_WIN_ENA_MASK 0x1 + +#define IO_WIN_9_CTRL_OFFSET 0x98 +#define IO_WIN_9_BASE_OFFSET 0x9C + +/* Mbus decoding unit IDs and attributes */ +#define MBUS_BOOTROM_TGT_ID 0x1 +#define MBUS_BOOTROM_ATTR 0x1D + +/* Internal Units Sync Barrier Control Register */ +#define MV_SYNC_BARRIER_CTRL 0x84 +#define MV_SYNC_BARRIER_CTRL_ALL 0xFFFF +#endif #define WIN_REG_IDX_RD(pre,reg,off,base) \ static __inline uint32_t \ pre ## _ ## reg ## _read(int i) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off(i))); \ } #define WIN_REG_IDX_RD2(pre,reg,off,base) \ static __inline uint32_t \ pre ## _ ## reg ## _read(int i, int j) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off(i, j))); \ } \ #define WIN_REG_BASE_IDX_RD(pre,reg,off) \ static __inline uint32_t \ pre ## _ ## reg ## _read(uint32_t base, int i) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off(i))); \ } #define WIN_REG_BASE_IDX_RD2(pre,reg,off) \ static __inline uint32_t \ pre ## _ ## reg ## _read(uint32_t base, int i, int j) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off(i, j))); \ } #define WIN_REG_IDX_WR(pre,reg,off,base) \ static __inline void \ pre ## _ ## reg ## _write(int i, uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off(i), val); \ } #define WIN_REG_IDX_WR2(pre,reg,off,base) \ static __inline void \ pre ## _ ## reg ## _write(int i, int j, uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off(i, j), val); \ } #define WIN_REG_BASE_IDX_WR(pre,reg,off) \ static __inline void \ pre ## _ ## reg ## _write(uint32_t base, int i, uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off(i), val); \ } #define WIN_REG_BASE_IDX_WR2(pre,reg,off) \ static __inline void \ pre ## _ ## reg ## _write(uint32_t base, int i, int j, uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off(i, j), val); \ } #define WIN_REG_RD(pre,reg,off,base) \ static __inline uint32_t \ pre ## _ ## reg ## _read(void) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off)); \ } #define WIN_REG_BASE_RD(pre,reg,off) \ static __inline uint32_t \ pre ## _ ## reg ## _read(uint32_t base) \ { \ return (bus_space_read_4(fdtbus_bs_tag, base, off)); \ } #define WIN_REG_WR(pre,reg,off,base) \ static __inline void \ pre ## _ ## reg ## _write(uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off, val); \ } #define WIN_REG_BASE_WR(pre,reg,off) \ static __inline void \ pre ## _ ## reg ## _write(uint32_t base, uint32_t val) \ { \ bus_space_write_4(fdtbus_bs_tag, base, off, val); \ } #endif /* _MVWIN_H_ */ Index: projects/release-pkg/sys/arm/mv/timer.c =================================================================== --- projects/release-pkg/sys/arm/mv/timer.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/timer.c (revision 294448) @@ -1,447 +1,496 @@ /*- * Copyright (c) 2006 Benno Rice. * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Adapted to Marvell SoC by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_timer.c, rev 1 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INITIAL_TIMECOUNTER (0xffffffff) #define MAX_WATCHDOG_TICKS (0xffffffff) -#if defined(SOC_MV_ARMADAXP) +#define MV_TMR 0x1 +#define MV_WDT 0x2 +#define MV_NONE 0x0 + +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) #define MV_CLOCK_SRC 25000000 /* Timers' 25MHz mode */ #else #define MV_CLOCK_SRC get_tclk() #endif +#if defined(SOC_MV_ARMADA38X) +#define WATCHDOG_TIMER 4 +#else +#define WATCHDOG_TIMER 2 +#endif + struct mv_timer_softc { struct resource * timer_res[2]; bus_space_tag_t timer_bst; bus_space_handle_t timer_bsh; struct mtx timer_mtx; struct eventtimer et; + boolean_t has_wdt; }; static struct resource_spec mv_timer_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, { -1, 0 } }; +/* Interrupt is not required by MV_WDT devices */ +static struct ofw_compat_data mv_timer_compat[] = { + {"mrvl,timer", MV_TMR | MV_WDT }, + {"marvell,armada-380-wdt", MV_WDT }, + {NULL, MV_NONE } +}; + static struct mv_timer_softc *timer_softc = NULL; static int timers_initialized = 0; static int mv_timer_probe(device_t); static int mv_timer_attach(device_t); static int mv_hardclock(void *); static unsigned mv_timer_get_timecount(struct timecounter *); static uint32_t mv_get_timer_control(void); static void mv_set_timer_control(uint32_t); static uint32_t mv_get_timer(uint32_t); static void mv_set_timer(uint32_t, uint32_t); static void mv_set_timer_rel(uint32_t, uint32_t); static void mv_watchdog_enable(void); static void mv_watchdog_disable(void); static void mv_watchdog_event(void *, unsigned int, int *); static int mv_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period); static int mv_timer_stop(struct eventtimer *et); static void mv_setup_timers(void); static struct timecounter mv_timer_timecounter = { .tc_get_timecount = mv_timer_get_timecount, .tc_name = "CPUTimer1", .tc_frequency = 0, /* This is assigned on the fly in the init sequence */ .tc_counter_mask = ~0u, .tc_quality = 1000, }; static int mv_timer_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "mrvl,timer")) + if (ofw_bus_search_compatible(dev, mv_timer_compat)->ocd_data == MV_NONE) return (ENXIO); device_set_desc(dev, "Marvell CPU Timer"); return (0); } static int mv_timer_attach(device_t dev) { int error; void *ihl; struct mv_timer_softc *sc; -#if !defined(SOC_MV_ARMADAXP) +#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X) uint32_t irq_cause, irq_mask; #endif if (timer_softc != NULL) return (ENXIO); sc = (struct mv_timer_softc *)device_get_softc(dev); timer_softc = sc; error = bus_alloc_resources(dev, mv_timer_spec, sc->timer_res); if (error) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->timer_bst = rman_get_bustag(sc->timer_res[0]); sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]); + sc->has_wdt = ofw_bus_has_prop(dev, "mrvl,has-wdt") || + ofw_bus_is_compatible(dev, "marvell,armada-380-wdt"); + mtx_init(&timer_softc->timer_mtx, "watchdog", NULL, MTX_DEF); - mv_watchdog_disable(); - EVENTHANDLER_REGISTER(watchdog_list, mv_watchdog_event, sc, 0); + if (sc->has_wdt) { + mv_watchdog_disable(); + EVENTHANDLER_REGISTER(watchdog_list, mv_watchdog_event, sc, 0); + } + + if (ofw_bus_search_compatible(dev, mv_timer_compat)->ocd_data + == MV_WDT) { + /* Don't set timers for wdt-only entry. */ + device_printf(dev, "only watchdog attached\n"); + return (0); + } else if (sc->timer_res[1] == NULL) { + device_printf(dev, "no interrupt resource\n"); + bus_release_resources(dev, mv_timer_spec, sc->timer_res); + return (ENXIO); + } + if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK, mv_hardclock, NULL, sc, &ihl) != 0) { bus_release_resources(dev, mv_timer_spec, sc->timer_res); device_printf(dev, "Could not setup interrupt.\n"); return (ENXIO); } mv_setup_timers(); -#if !defined(SOC_MV_ARMADAXP) +#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X) irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE); irq_cause &= IRQ_TIMER0_CLR; write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause); irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK); irq_mask |= IRQ_TIMER0_MASK; irq_mask &= ~IRQ_TIMER1_MASK; write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask); #endif sc->et.et_name = "CPUTimer0"; sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; sc->et.et_quality = 1000; sc->et.et_frequency = MV_CLOCK_SRC; sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = mv_timer_start; sc->et.et_stop = mv_timer_stop; sc->et.et_priv = sc; et_register(&sc->et); mv_timer_timecounter.tc_frequency = MV_CLOCK_SRC; tc_init(&mv_timer_timecounter); return (0); } static int mv_hardclock(void *arg) { struct mv_timer_softc *sc; uint32_t irq_cause; irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE); irq_cause &= IRQ_TIMER0_CLR; write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause); sc = (struct mv_timer_softc *)arg; if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } static device_method_t mv_timer_methods[] = { DEVMETHOD(device_probe, mv_timer_probe), DEVMETHOD(device_attach, mv_timer_attach), { 0, 0 } }; static driver_t mv_timer_driver = { "timer", mv_timer_methods, sizeof(struct mv_timer_softc), }; static devclass_t mv_timer_devclass; DRIVER_MODULE(timer, simplebus, mv_timer_driver, mv_timer_devclass, 0, 0); static unsigned mv_timer_get_timecount(struct timecounter *tc) { return (INITIAL_TIMECOUNTER - mv_get_timer(1)); } void DELAY(int usec) { uint32_t val, val_temp; int32_t nticks; if (!timers_initialized) { for (; usec > 0; usec--) for (val = 100; val > 0; val--) __asm __volatile("nop" ::: "memory"); return; } val = mv_get_timer(1); nticks = ((MV_CLOCK_SRC / 1000000 + 1) * usec); while (nticks > 0) { val_temp = mv_get_timer(1); if (val > val_temp) nticks -= (val - val_temp); else nticks -= (val + (INITIAL_TIMECOUNTER - val_temp)); val = val_temp; } } static uint32_t mv_get_timer_control(void) { return (bus_space_read_4(timer_softc->timer_bst, timer_softc->timer_bsh, CPU_TIMER_CONTROL)); } static void mv_set_timer_control(uint32_t val) { bus_space_write_4(timer_softc->timer_bst, timer_softc->timer_bsh, CPU_TIMER_CONTROL, val); } static uint32_t mv_get_timer(uint32_t timer) { return (bus_space_read_4(timer_softc->timer_bst, timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8)); } static void mv_set_timer(uint32_t timer, uint32_t val) { bus_space_write_4(timer_softc->timer_bst, timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8, val); } static void mv_set_timer_rel(uint32_t timer, uint32_t val) { bus_space_write_4(timer_softc->timer_bst, timer_softc->timer_bsh, CPU_TIMER0_REL + timer * 0x8, val); } static void mv_watchdog_enable(void) { uint32_t val, irq_cause; -#if !defined(SOC_MV_ARMADAXP) +#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X) uint32_t irq_mask; #endif irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE); irq_cause &= IRQ_TIMER_WD_CLR; write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause); -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) val = read_cpu_mp_clocks(WD_RSTOUTn_MASK); val |= (WD_GLOBAL_MASK | WD_CPU0_MASK); write_cpu_mp_clocks(WD_RSTOUTn_MASK, val); + + val = read_cpu_misc(RSTOUTn_MASK); + val &= ~RSTOUTn_MASK_WD; + write_cpu_misc(RSTOUTn_MASK, val); #else irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK); irq_mask |= IRQ_TIMER_WD_MASK; write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask); val = read_cpu_ctrl(RSTOUTn_MASK); val |= WD_RST_OUT_EN; write_cpu_ctrl(RSTOUTn_MASK, val); #endif val = mv_get_timer_control(); - val |= CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO; -#if defined(SOC_MV_ARMADAXP) - val |= CPU_TIMER_WD_25MHZ_EN; +#if defined(SOC_MV_ARMADA38X) + val |= CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO | CPU_TIMER_WD_25MHZ_EN; +#elif defined(SOC_MV_ARMADAXP) + val |= CPU_TIMER2_EN | CPU_TIMER2_AUTO | CPU_TIMER_WD_25MHZ_EN; +#else + val |= CPU_TIMER2_EN | CPU_TIMER2_AUTO; #endif mv_set_timer_control(val); } static void mv_watchdog_disable(void) { uint32_t val, irq_cause; -#if !defined(SOC_MV_ARMADAXP) +#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X) uint32_t irq_mask; #endif val = mv_get_timer_control(); +#if defined(SOC_MV_ARMADA38X) val &= ~(CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO); +#else + val &= ~(CPU_TIMER2_EN | CPU_TIMER2_AUTO); +#endif mv_set_timer_control(val); -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) val = read_cpu_mp_clocks(WD_RSTOUTn_MASK); val &= ~(WD_GLOBAL_MASK | WD_CPU0_MASK); write_cpu_mp_clocks(WD_RSTOUTn_MASK, val); + + val = read_cpu_misc(RSTOUTn_MASK); + val |= RSTOUTn_MASK_WD; + write_cpu_misc(RSTOUTn_MASK, RSTOUTn_MASK_WD); #else val = read_cpu_ctrl(RSTOUTn_MASK); val &= ~WD_RST_OUT_EN; write_cpu_ctrl(RSTOUTn_MASK, val); irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK); irq_mask &= ~(IRQ_TIMER_WD_MASK); write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask); #endif irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE); irq_cause &= IRQ_TIMER_WD_CLR; write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause); } /* * Watchdog event handler. */ static void mv_watchdog_event(void *arg, unsigned int cmd, int *error) { uint64_t ns; uint64_t ticks; mtx_lock(&timer_softc->timer_mtx); if (cmd == 0) mv_watchdog_disable(); else { /* * Watchdog timeout is in nanosecs, calculation according to * watchdog(9) */ ns = (uint64_t)1 << (cmd & WD_INTERVAL); ticks = (uint64_t)(ns * MV_CLOCK_SRC) / 1000000000; if (ticks > MAX_WATCHDOG_TICKS) mv_watchdog_disable(); else { - /* Timer 2 is the watchdog */ - mv_set_timer(2, ticks); + mv_set_timer(WATCHDOG_TIMER, ticks); mv_watchdog_enable(); *error = 0; } } mtx_unlock(&timer_softc->timer_mtx); } static int mv_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct mv_timer_softc *sc; uint32_t val, val1; /* Calculate dividers. */ sc = (struct mv_timer_softc *)et->et_priv; if (period != 0) val = ((uint32_t)sc->et.et_frequency * period) >> 32; else val = 0; if (first != 0) val1 = ((uint32_t)sc->et.et_frequency * first) >> 32; else val1 = val; /* Apply configuration. */ mv_set_timer_rel(0, val); mv_set_timer(0, val1); val = mv_get_timer_control(); val |= CPU_TIMER0_EN; if (period != 0) val |= CPU_TIMER0_AUTO; else val &= ~CPU_TIMER0_AUTO; mv_set_timer_control(val); return (0); } static int mv_timer_stop(struct eventtimer *et) { uint32_t val; val = mv_get_timer_control(); val &= ~(CPU_TIMER0_EN | CPU_TIMER0_AUTO); mv_set_timer_control(val); return (0); } static void mv_setup_timers(void) { uint32_t val; mv_set_timer_rel(1, INITIAL_TIMECOUNTER); mv_set_timer(1, INITIAL_TIMECOUNTER); val = mv_get_timer_control(); val &= ~(CPU_TIMER0_EN | CPU_TIMER0_AUTO); val |= CPU_TIMER1_EN | CPU_TIMER1_AUTO; -#if defined(SOC_MV_ARMADAXP) +#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) /* Enable 25MHz mode */ val |= CPU_TIMER0_25MHZ_EN | CPU_TIMER1_25MHZ_EN; #endif mv_set_timer_control(val); timers_initialized = 1; } Index: projects/release-pkg/sys/arm/mv/twsi.c =================================================================== --- projects/release-pkg/sys/arm/mv/twsi.c (revision 294447) +++ projects/release-pkg/sys/arm/mv/twsi.c (revision 294448) @@ -1,641 +1,647 @@ /*- * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell * SoCs. Supports master operation only, and works in polling mode. * * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices". */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #define MV_TWSI_NAME "twsi" #define IICBUS_DEVNAME "iicbus" #define TWSI_SLAVE_ADDR 0x00 #define TWSI_EXT_SLAVE_ADDR 0x10 #define TWSI_DATA 0x04 #define TWSI_CONTROL 0x08 #define TWSI_CONTROL_ACK (1 << 2) #define TWSI_CONTROL_IFLG (1 << 3) #define TWSI_CONTROL_STOP (1 << 4) #define TWSI_CONTROL_START (1 << 5) #define TWSI_CONTROL_TWSIEN (1 << 6) #define TWSI_CONTROL_INTEN (1 << 7) #define TWSI_STATUS 0x0c #define TWSI_STATUS_START 0x08 #define TWSI_STATUS_RPTD_START 0x10 #define TWSI_STATUS_ADDR_W_ACK 0x18 #define TWSI_STATUS_DATA_WR_ACK 0x28 #define TWSI_STATUS_ADDR_R_ACK 0x40 #define TWSI_STATUS_DATA_RD_ACK 0x50 #define TWSI_STATUS_DATA_RD_NOACK 0x58 #define TWSI_BAUD_RATE 0x0c #define TWSI_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) #define TWSI_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) #define TWSI_BAUD_RATE_SLOW 50000 /* 50kHz */ #define TWSI_BAUD_RATE_FAST 100000 /* 100kHz */ #define TWSI_SOFT_RESET 0x1c #define TWSI_DEBUG #undef TWSI_DEBUG #ifdef TWSI_DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif struct mv_twsi_softc { device_t dev; struct resource *res[1]; /* SYS_RES_MEMORY */ struct mtx mutex; device_t iicbus; }; static struct mv_twsi_baud_rate { uint32_t raw; int param; int m; int n; } baud_rate[IIC_FASTEST + 1]; static int mv_twsi_probe(device_t); static int mv_twsi_attach(device_t); static int mv_twsi_detach(device_t); static int mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout); static int mv_twsi_start(device_t dev, u_char slave, int timeout); static int mv_twsi_stop(device_t dev); static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay); static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout); static struct resource_spec res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; +static struct ofw_compat_data compat_data[] = { + { "mrvl,twsi", true }, + { "marvell,mv64xxx-i2c", true }, + { NULL, false } +}; + static device_method_t mv_twsi_methods[] = { /* device interface */ DEVMETHOD(device_probe, mv_twsi_probe), DEVMETHOD(device_attach, mv_twsi_attach), DEVMETHOD(device_detach, mv_twsi_detach), /* iicbus interface */ DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start), DEVMETHOD(iicbus_start, mv_twsi_start), DEVMETHOD(iicbus_stop, mv_twsi_stop), DEVMETHOD(iicbus_write, mv_twsi_write), DEVMETHOD(iicbus_read, mv_twsi_read), DEVMETHOD(iicbus_reset, mv_twsi_reset), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), { 0, 0 } }; static devclass_t mv_twsi_devclass; static driver_t mv_twsi_driver = { MV_TWSI_NAME, mv_twsi_methods, sizeof(struct mv_twsi_softc), }; DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0); DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0); MODULE_DEPEND(twsi, iicbus, 1, 1, 1); static __inline uint32_t TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off) { return (bus_read_4(sc->res[0], off)); } static __inline void TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->res[0], off, val); } static __inline void twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask) { uint32_t val; val = TWSI_READ(sc, TWSI_CONTROL); val &= ~mask; TWSI_WRITE(sc, TWSI_CONTROL, val); } static __inline void twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask) { uint32_t val; val = TWSI_READ(sc, TWSI_CONTROL); val |= mask; TWSI_WRITE(sc, TWSI_CONTROL, val); } static __inline void twsi_clear_iflg(struct mv_twsi_softc *sc) { DELAY(1000); twsi_control_clear(sc, TWSI_CONTROL_IFLG); DELAY(1000); } /* * timeout given in us * returns * 0 on sucessfull mask change * non-zero on timeout */ static int twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask) { timeout /= 10; while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) { DELAY(10); if (--timeout < 0) return (timeout); } return (0); } /* * 'timeout' is given in us. Note also that timeout handling is not exact -- * twsi_locked_start() total wait can be more than 2 x timeout * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START * or TWSI_STATUS_RPTD_START */ static int twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask, u_char slave, int timeout) { int read_access, iflg_set = 0; uint32_t status; mtx_assert(&sc->mutex, MA_OWNED); if (mask == TWSI_STATUS_RPTD_START) /* read IFLG to know if it should be cleared later; from NBSD */ iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG; twsi_control_set(sc, TWSI_CONTROL_START); if (mask == TWSI_STATUS_RPTD_START && iflg_set) { debugf("IFLG set, clearing\n"); twsi_clear_iflg(sc); } /* * Without this delay we timeout checking IFLG if the timeout is 0. * NBSD driver always waits here too. */ DELAY(1000); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout sending %sSTART condition\n", mask == TWSI_STATUS_START ? "" : "repeated "); return (IIC_ETIMEOUT); } status = TWSI_READ(sc, TWSI_STATUS); if (status != mask) { debugf("wrong status (%02x) after sending %sSTART condition\n", status, mask == TWSI_STATUS_START ? "" : "repeated "); return (IIC_ESTATUS); } TWSI_WRITE(sc, TWSI_DATA, slave); DELAY(1000); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout sending slave address\n"); return (IIC_ETIMEOUT); } read_access = (slave & 0x1) ? 1 : 0; status = TWSI_READ(sc, TWSI_STATUS); if (status != (read_access ? TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) { debugf("no ACK (status: %02x) after sending slave address\n", status); return (IIC_ENOACK); } return (IIC_NOERR); } static int mv_twsi_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "mrvl,twsi")) + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Marvell Integrated I2C Bus Controller"); return (BUS_PROBE_DEFAULT); } #define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a)) static void mv_twsi_cal_baud_rate(const uint32_t target, struct mv_twsi_baud_rate *rate) { uint32_t clk, cur, diff, diff0; int m, n, m0, n0; /* Calculate baud rate. */ m0 = n0 = 4; /* Default values on reset */ diff0 = 0xffffffff; clk = get_tclk(); for (n = 0; n < 8; n++) { for (m = 0; m < 16; m++) { cur = TWSI_BAUD_RATE_RAW(clk,m,n); diff = ABSSUB(target, cur); if (diff < diff0) { m0 = m; n0 = n; diff0 = diff; } } } rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0); rate->param = TWSI_BAUD_RATE_PARAM(m0, n0); rate->m = m0; rate->n = n0; } static int mv_twsi_attach(device_t dev) { struct mv_twsi_softc *sc; phandle_t child, iicbusnode; device_t childdev; struct iicbus_ivar *devi; char dname[32]; /* 32 is taken from struct u_device */ uint32_t paddr; int len, error; sc = device_get_softc(dev); sc->dev = dev; bzero(baud_rate, sizeof(baud_rate)); mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF); /* Allocate IO resources */ if (bus_alloc_resources(dev, res_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); mv_twsi_detach(dev); return (ENXIO); } mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &baud_rate[IIC_SLOW]); mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &baud_rate[IIC_FAST]); if (bootverbose) device_printf(dev, "calculated baud rates are:\n" " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n" " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n", baud_rate[IIC_SLOW].raw / 1000, baud_rate[IIC_SLOW].m, baud_rate[IIC_SLOW].n, baud_rate[IIC_FAST].raw / 1000, baud_rate[IIC_FAST].m, baud_rate[IIC_FAST].n); sc->iicbus = device_add_child(dev, IICBUS_DEVNAME, -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child\n"); mv_twsi_detach(dev); return (ENXIO); } /* Attach iicbus. */ bus_generic_attach(dev); iicbusnode = 0; /* Find iicbus as the child devices in the device tree. */ for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; error = OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (error == -1) continue; len = strlen(dname); if (len == strlen(IICBUS_DEVNAME) && strncasecmp(dname, IICBUS_DEVNAME, len) == 0) { iicbusnode = child; break; } } if (iicbusnode == 0) goto attach_end; /* Attach child devices onto iicbus. */ for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) { /* Get slave address. */ error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)); if (error == -1) error = OF_getprop(child, "reg", &paddr, sizeof(paddr)); if (error == -1) continue; /* Get device driver name. */ len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (bootverbose) device_printf(dev, "adding a device %s at %d.\n", dname, fdt32_to_cpu(paddr)); childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1); devi = IICBUS_IVAR(childdev); devi->addr = fdt32_to_cpu(paddr); } attach_end: bus_generic_attach(sc->iicbus); return (0); } static int mv_twsi_detach(device_t dev) { struct mv_twsi_softc *sc; int rv; sc = device_get_softc(dev); if ((rv = bus_generic_detach(dev)) != 0) return (rv); if (sc->iicbus != NULL) if ((rv = device_delete_child(dev, sc->iicbus)) != 0) return (rv); bus_release_resources(dev, res_spec, sc->res); mtx_destroy(&sc->mutex); return (0); } /* * Only slave mode supported, disregard [old]addr */ static int mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { struct mv_twsi_softc *sc; uint32_t param; sc = device_get_softc(dev); switch (speed) { case IIC_SLOW: case IIC_FAST: param = baud_rate[speed].param; break; case IIC_FASTEST: case IIC_UNKNOWN: default: param = baud_rate[IIC_FAST].param; break; } mtx_lock(&sc->mutex); TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0); DELAY(2000); TWSI_WRITE(sc, TWSI_BAUD_RATE, param); TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK); DELAY(1000); mtx_unlock(&sc->mutex); return (0); } /* * timeout is given in us */ static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout) { struct mv_twsi_softc *sc; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave, timeout); mtx_unlock(&sc->mutex); if (rv) { mv_twsi_stop(dev); return (rv); } else return (IIC_NOERR); } /* * timeout is given in us */ static int mv_twsi_start(device_t dev, u_char slave, int timeout) { struct mv_twsi_softc *sc; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout); mtx_unlock(&sc->mutex); if (rv) { mv_twsi_stop(dev); return (rv); } else return (IIC_NOERR); } static int mv_twsi_stop(device_t dev) { struct mv_twsi_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->mutex); twsi_control_set(sc, TWSI_CONTROL_STOP); DELAY(1000); twsi_clear_iflg(sc); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct mv_twsi_softc *sc; uint32_t status; int last_byte, rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); *read = 0; while (*read < len) { /* * Check if we are reading last byte of the last buffer, * do not send ACK then, per I2C specs */ last_byte = ((*read == len - 1) && last) ? 1 : 0; if (last_byte) twsi_control_clear(sc, TWSI_CONTROL_ACK); else twsi_control_set(sc, TWSI_CONTROL_ACK); DELAY (1000); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) { debugf("timeout reading data\n"); rv = IIC_ETIMEOUT; goto out; } status = TWSI_READ(sc, TWSI_STATUS); if (status != (last_byte ? TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) { debugf("wrong status (%02x) while reading\n", status); rv = IIC_ESTATUS; goto out; } *buf++ = TWSI_READ(sc, TWSI_DATA); (*read)++; } rv = IIC_NOERR; out: mtx_unlock(&sc->mutex); return (rv); } static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout) { struct mv_twsi_softc *sc; uint32_t status; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); *sent = 0; while (*sent < len) { TWSI_WRITE(sc, TWSI_DATA, *buf++); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout writing data\n"); rv = IIC_ETIMEOUT; goto out; } status = TWSI_READ(sc, TWSI_STATUS); if (status != TWSI_STATUS_DATA_WR_ACK) { debugf("wrong status (%02x) while writing\n", status); rv = IIC_ESTATUS; goto out; } (*sent)++; } rv = IIC_NOERR; out: mtx_unlock(&sc->mutex); return (rv); } Index: projects/release-pkg/sys/arm64/conf/GENERIC =================================================================== --- projects/release-pkg/sys/arm64/conf/GENERIC (revision 294447) +++ projects/release-pkg/sys/arm64/conf/GENERIC (revision 294448) @@ -1,158 +1,157 @@ # # GENERIC -- Generic kernel configuration file for FreeBSD/arm64 # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ cpu ARM64 ident GENERIC makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support options SCHED_ULE # ULE scheduler options PREEMPTION # Enable kernel thread preemption options INET # InterNETworking options INET6 # IPv6 communications protocols options IPSEC # IP (v4/v6) security options TCP_OFFLOAD # TCP offload options SCTP # Stream Control Transmission Protocol options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling options QUOTA # Enable disk quotas for UFS options MD_ROOT # MD is a potential root device options NFSCL # Network Filesystem Client options NFSD # Network Filesystem Server options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework options GEOM_PART_GPT # GUID Partition Tables. options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI options KTRACE # ktrace(1) support options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options KBD_INSTALL_CDEV # install a CDEV entry in /dev options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing options CAPABILITY_MODE # Capsicum capability mode options CAPABILITIES # Capsicum capabilities options MAC # TrustedBSD MAC Framework options KDTRACE_FRAME # Ensure frames are compiled in options KDTRACE_HOOKS # Kernel DTrace hooks options VFP # Floating-point support -options VFS_AIO # Real implementations of the aio_* system calls options RACCT # Resource accounting framework options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default options RCTL # Resource limits options SMP # Debugging support. Always need this: options KDB # Enable kernel debugger support. options KDB_TRACE # Print a stack trace for a panic. # For full debugger support use (turn off in stable branch): options DDB # Support DDB. #options GDB # Support remote GDB. options DEADLKRES # Enable the deadlock resolver options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones # SoC support options SOC_CAVM_THUNDERX options SOC_HISI_HI6220 # VirtIO support device virtio device virtio_mmio device virtio_blk device vtnet # Bus drivers device pci options PCI_IOV # PCI SR-IOV support # Ethernet NICs device mii device miibus # MII bus support device em # Intel PRO/1000 Gigabit Ethernet Family device igb # Intel PRO/1000 PCIE Server Gigabit Family device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet device vnic # Cavium ThunderX NIC # Block devices device ahci device scbus device da # ATA/SCSI peripherals device pass # Passthrough device (direct ATA/SCSI access) # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards device dwmmc # Serial (COM) ports device uart # Generic UART driver device pl011 # USB support options USB_DEBUG # enable debug msgs device dwcotg # DWC OTG controller device xhci # XHCI PCI->USB interface (USB 3.0) device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da # Pseudo devices. device loop # Network loopback device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tun # Packet tunnel. device md # Memory "disks" device gif # IPv6 and IPv4 tunneling device firmware # firmware assist module device psci # Support for ARM PSCI # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! # Note that 'bpf' is required for DHCP. device bpf # Berkeley packet filter # Chip-specific errata options THUNDERX_PASS_1_1_ERRATA options FDT device acpi # The crypto framework is required by IPSEC device crypto # Required by IPSEC Index: projects/release-pkg/sys/boot/fdt/dts/arm/armada-380.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/armada-380.dtsi (nonexistent) +++ projects/release-pkg/sys/boot/fdt/dts/arm/armada-380.dtsi (revision 294448) @@ -0,0 +1,154 @@ +/* + * Device Tree Include file for Marvell Armada 380 SoC. + * + * Copyright (C) 2014 Marvell + * + * Lior Amsalem + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +#include "armada-38x.dtsi" + +/ { + model = "Marvell Armada 380 family SoC"; + compatible = "marvell,armada380"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "marvell,armada-380-smp"; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + }; + + soc { + internal-regs { + pinctrl@18000 { + compatible = "marvell,mv88f6810-pinctrl"; + }; + }; + + pcie-controller { + compatible = "marvell,armada-370-pcie"; + status = "disabled"; + device_type = "pci"; + + #address-cells = <3>; + #size-cells = <2>; + + msi-parent = <&mpic>; + bus-range = <0x00 0xff>; + + ranges = + <0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 + 0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 + 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 + 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 + 0x82000000 0x1 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 0 MEM */ + 0x81000000 0x1 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 0 IO */ + 0x82000000 0x2 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 1 MEM */ + 0x81000000 0x2 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 1 IO */ + 0x82000000 0x3 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 2 MEM */ + 0x81000000 0x3 0 MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 2 IO */>; + + /* x1 port */ + pcie@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x80000 0 0x2000>; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0 + 0x81000000 0 0 0x81000000 0x1 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 8>; + status = "disabled"; + }; + + /* x1 port */ + pcie@2,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x40000 0 0x2000>; + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 + 0x81000000 0 0 0x81000000 0x2 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 5>; + status = "disabled"; + }; + + /* x1 port */ + pcie@3,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x44000 0 0x2000>; + reg = <0x1800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0 + 0x81000000 0 0 0x81000000 0x3 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; + marvell,pcie-port = <2>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 6>; + status = "disabled"; + }; + }; + }; +}; Property changes on: projects/release-pkg/sys/boot/fdt/dts/arm/armada-380.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/boot/fdt/dts/arm/armada-385.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/armada-385.dtsi (nonexistent) +++ projects/release-pkg/sys/boot/fdt/dts/arm/armada-385.dtsi (revision 294448) @@ -0,0 +1,81 @@ +/* + * Device Tree Include file for Marvell Armada 385 SoC. + * + * Copyright (C) 2014 Marvell + * + * Lior Amsalem + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +#include "armada-38x.dtsi" + +/ { + model = "Marvell Armada 385 family SoC"; + compatible = "marvell,armada385", "marvell,armada380"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "marvell,armada-380-smp"; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + }; + }; + + soc { + internal-regs { + pinctrl@18000 { + compatible = "marvell,mv88f6820-pinctrl"; + }; + }; + }; +}; Property changes on: projects/release-pkg/sys/boot/fdt/dts/arm/armada-385.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/boot/fdt/dts/arm/armada-388-gp.dts =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/armada-388-gp.dts (nonexistent) +++ projects/release-pkg/sys/boot/fdt/dts/arm/armada-388-gp.dts (revision 294448) @@ -0,0 +1,393 @@ +/* + * Device Tree file for Marvell Armada 385 development board + * (RD-88F6820-GP) + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +/dts-v1/; +#include "armada-388.dtsi" +#include + +/ { + model = "Marvell Armada 385 GP"; + compatible = "marvell,a385-gp", "marvell,armada388", "marvell,armada380"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x80000000>; /* 2 GB */ + }; + + soc { + ranges = <0 0 0xf1000000 0x100000>; + + internal-regs { + spi@10600 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + status = "okay"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p128", "jedec,spi-nor"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <50000000>; + m25p,fast-read; + }; + }; + + i2c@11000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + clock-frequency = <100000>; + /* + * The EEPROM located at adresse 54 is needed + * for the boot - DO NOT ERASE IT - + */ + + expander0: pca9555@20 { + compatible = "nxp,pca9555"; + pinctrl-names = "default"; + pinctrl-0 = <&pca0_pins>; + interrupt-parent = <&gpio0>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x20>; + }; + + expander1: pca9555@21 { + compatible = "nxp,pca9555"; + pinctrl-names = "default"; + interrupt-parent = <&gpio0>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x21>; + }; + + }; + + serial@12000 { + /* + * Exported on the micro USB connector CON16 + * through an FTDI + */ + + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; + + /* GE1 CON15 */ + ethernet@30000 { + pinctrl-names = "default"; + pinctrl-0 = <&ge1_rgmii_pins>; + status = "okay"; + phy = <&phy1>; + phy-mode = "rgmii-id"; + }; + + /* CON4 */ + usb@58000 { + vcc-supply = <®_usb2_0_vbus>; + status = "okay"; + }; + + /* GE0 CON1 */ + ethernet@70000 { + pinctrl-names = "default"; + /* + * The Reference Clock 0 is used to provide a + * clock to the PHY + */ + pinctrl-0 = <&ge0_rgmii_pins>, <&ref_clk0_pins>; + status = "okay"; + phy = <&phy0>; + phy-mode = "rgmii-id"; + }; + + + mdio@72004 { + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins>; + + phy0: ethernet-phy@1 { + reg = <1>; + }; + + phy1: ethernet-phy@0 { + reg = <0>; + }; + }; + + sata@a8000 { + pinctrl-names = "default"; + pinctrl-0 = <&sata0_pins>, <&sata1_pins>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + sata0: sata-port@0 { + reg = <0>; + target-supply = <®_5v_sata0>; + }; + + sata1: sata-port@1 { + reg = <1>; + target-supply = <®_5v_sata1>; + }; + }; + + sata@e0000 { + pinctrl-names = "default"; + pinctrl-0 = <&sata2_pins>, <&sata3_pins>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + sata2: sata-port@0 { + reg = <0>; + target-supply = <®_5v_sata2>; + }; + + sata3: sata-port@1 { + reg = <1>; + target-supply = <®_5v_sata3>; + }; + }; + + sdhci@d8000 { + pinctrl-names = "default"; + pinctrl-0 = <&sdhci_pins>; + cd-gpios = <&expander0 5 GPIO_ACTIVE_LOW>; + no-1-8-v; + wp-inverted; + bus-width = <8>; + status = "okay"; + }; + + /* CON5 */ + usb3@f0000 { + vcc-supply = <®_usb2_1_vbus>; + status = "okay"; + }; + + /* CON7 */ + usb3@f8000 { + vcc-supply = <®_usb3_vbus>; + status = "okay"; + }; + }; + + gpio-fan { + compatible = "gpio-fan"; + gpios = <&expander1 3 GPIO_ACTIVE_HIGH>; + gpio-fan,speed-map = < 0 0 + 3000 1>; + }; + }; + + pci0: pcie@f1080000 { + status = "okay"; + }; + + reg_usb3_vbus: usb3-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb3-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + gpio = <&expander1 15 GPIO_ACTIVE_HIGH>; + }; + + reg_usb2_0_vbus: v5-vbus0 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-vbus0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + gpio = <&expander1 14 GPIO_ACTIVE_HIGH>; + }; + + reg_usb2_1_vbus: v5-vbus1 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-vbus1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + gpio = <&expander0 4 GPIO_ACTIVE_HIGH>; + }; + + reg_usb2_1_vbus: v5-vbus1 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-vbus1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + gpio = <&expander0 4 GPIO_ACTIVE_HIGH>; + }; + + reg_sata0: pwr-sata0 { + compatible = "regulator-fixed"; + regulator-name = "pwr_en_sata0"; + enable-active-high; + regulator-always-on; + + }; + + reg_5v_sata0: v5-sata0 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-sata0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <®_sata0>; + }; + + reg_12v_sata0: v12-sata0 { + compatible = "regulator-fixed"; + regulator-name = "v12.0-sata0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + vin-supply = <®_sata0>; + }; + + reg_sata1: pwr-sata1 { + regulator-name = "pwr_en_sata1"; + compatible = "regulator-fixed"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + enable-active-high; + regulator-always-on; + gpio = <&expander0 3 GPIO_ACTIVE_HIGH>; + }; + + reg_5v_sata1: v5-sata1 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-sata1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <®_sata1>; + }; + + reg_12v_sata1: v12-sata1 { + compatible = "regulator-fixed"; + regulator-name = "v12.0-sata1"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + vin-supply = <®_sata1>; + }; + + reg_sata2: pwr-sata2 { + compatible = "regulator-fixed"; + regulator-name = "pwr_en_sata2"; + enable-active-high; + regulator-always-on; + gpio = <&expander0 11 GPIO_ACTIVE_HIGH>; + }; + + reg_5v_sata2: v5-sata2 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-sata2"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <®_sata2>; + }; + + reg_12v_sata2: v12-sata2 { + compatible = "regulator-fixed"; + regulator-name = "v12.0-sata2"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + vin-supply = <®_sata2>; + }; + + reg_sata3: pwr-sata3 { + compatible = "regulator-fixed"; + regulator-name = "pwr_en_sata3"; + enable-active-high; + regulator-always-on; + gpio = <&expander0 12 GPIO_ACTIVE_HIGH>; + }; + + reg_5v_sata3: v5-sata3 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-sata3"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <®_sata3>; + }; + + reg_12v_sata3: v12-sata3 { + compatible = "regulator-fixed"; + regulator-name = "v12.0-sata3"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + vin-supply = <®_sata3>; + }; +}; + +&pinctrl { + pca0_pins: pca0_pins { + marvell,pins = "mpp18"; + marvell,function = "gpio"; + }; +}; Property changes on: projects/release-pkg/sys/boot/fdt/dts/arm/armada-388-gp.dts ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/boot/fdt/dts/arm/armada-388.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/armada-388.dtsi (nonexistent) +++ projects/release-pkg/sys/boot/fdt/dts/arm/armada-388.dtsi (revision 294448) @@ -0,0 +1,72 @@ +/* + * Device Tree Include file for Marvell Armada 388 SoC. + * + * Copyright (C) 2015 Marvell + * + * Gregory CLEMENT + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * The main difference with the Armada 385 is that the 388 can handle two more + * SATA ports. So we can reuse the dtsi of the Armada 385, override the pinctrl + * property and the name of the SoC, and add the second SATA host which control + * the 2 other ports. + * + * $FreeBSD$ + */ + +#include "armada-385.dtsi" + +/ { + model = "Marvell Armada 388 family SoC"; + compatible = "marvell,armada388", "marvell,armada385", + "marvell,armada380"; + + soc { + internal-regs { + pinctrl@18000 { + compatible = "marvell,mv88f6828-pinctrl"; + }; + + sata@e0000 { + compatible = "marvell,armada-380-ahci"; + reg = <0xe0000 0x2000>; + interrupts = ; + clocks = <&gateclk 30>; + status = "disabled"; + }; + + }; + }; +}; Property changes on: projects/release-pkg/sys/boot/fdt/dts/arm/armada-388.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/boot/fdt/dts/arm/armada-38x.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/armada-38x.dtsi (nonexistent) +++ projects/release-pkg/sys/boot/fdt/dts/arm/armada-38x.dtsi (revision 294448) @@ -0,0 +1,630 @@ +/* + * Device Tree Include file for Marvell Armada 38x family of SoCs. + * + * Copyright (C) 2014 Marvell + * + * Lior Amsalem + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +#include "skeleton.dtsi" +#include +#include + +#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) + +/ { + model = "Marvell Armada 38x family SoC"; + compatible = "marvell,armada380"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + serial0 = &uart0; + serial1 = &uart1; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts-extended = <&mpic 3>; + }; + + soc { + compatible = "marvell,armada380-mbus", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + controller = <&mbusc>; + interrupt-parent = <&gic>; + pcie-mem-aperture = <0xe0000000 0x8000000>; + pcie-io-aperture = <0xe8000000 0x100000>; + + bootrom { + compatible = "marvell,bootrom"; + reg = ; + }; + + devbus-bootcs { + compatible = "marvell,mvebu-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x2f) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + devbus-cs0 { + compatible = "marvell,mvebu-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x3e) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + devbus-cs1 { + compatible = "marvell,mvebu-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x3d) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + devbus-cs2 { + compatible = "marvell,mvebu-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x3b) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + devbus-cs3 { + compatible = "marvell,mvebu-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x37) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + internal-regs { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; + + L2: cache-controller@8000 { + compatible = "arm,pl310-cache"; + reg = <0x8000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + scu@c000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xc000 0x58>; + }; + + timer@c200 { + compatible = "arm,cortex-a9-global-timer"; + reg = <0xc200 0x20>; + interrupts = ; + clock-frequency = <800000000>; + clocks = <&coreclk 2>; + }; + + timer@c600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xc600 0x20>; + interrupts = ; + clock-frequency = <800000000>; + clocks = <&coreclk 2>; + }; + + gic: interrupt-controller@d000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #size-cells = <0>; + interrupt-controller; + reg = <0xd000 0x1000>, + <0xc100 0x100>; + }; + + spi0: spi@10600 { + compatible = "marvell,armada-380-spi", + "marvell,orion-spi"; + reg = <0x10600 0x50>; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + interrupts = ; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + spi1: spi@10680 { + compatible = "marvell,armada-380-spi", + "marvell,orion-spi"; + reg = <0x10680 0x50>; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + interrupts = ; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + i2c0: i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + timeout-ms = <1000>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + i2c1: i2c@11100 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11100 0x20>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + timeout-ms = <1000>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + uart0: serial@12000 { + compatible = "snps,dw-apb-uart"; + reg = <0x12000 0x100>; + reg-shift = <2>; + interrupts = ; + reg-io-width = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + uart1: serial@12100 { + compatible = "snps,dw-apb-uart"; + reg = <0x12100 0x100>; + reg-shift = <2>; + interrupts = ; + reg-io-width = <1>; + clocks = <&coreclk 0>; + status = "disabled"; + }; + + pinctrl: pinctrl@18000 { + reg = <0x18000 0x20>; + + ge0_rgmii_pins: ge-rgmii-pins-0 { + marvell,pins = "mpp6", "mpp7", "mpp8", + "mpp9", "mpp10", "mpp11", + "mpp12", "mpp13", "mpp14", + "mpp15", "mpp16", "mpp17"; + marvell,function = "ge0"; + }; + + ge1_rgmii_pins: ge-rgmii-pins-1 { + marvell,pins = "mpp21", "mpp27", "mpp28", + "mpp29", "mpp30", "mpp31", + "mpp32", "mpp37", "mpp38", + "mpp39", "mpp40", "mpp41"; + marvell,function = "ge1"; + }; + + i2c0_pins: i2c-pins-0 { + marvell,pins = "mpp2", "mpp3"; + marvell,function = "i2c0"; + }; + + mdio_pins: mdio-pins { + marvell,pins = "mpp4", "mpp5"; + marvell,function = "ge"; + }; + + ref_clk0_pins: ref-clk-pins-0 { + marvell,pins = "mpp45"; + marvell,function = "ref"; + }; + + ref_clk1_pins: ref-clk-pins-1 { + marvell,pins = "mpp46"; + marvell,function = "ref"; + }; + + spi0_pins: spi-pins-0 { + marvell,pins = "mpp22", "mpp23", "mpp24", + "mpp25"; + marvell,function = "spi0"; + }; + + spi1_pins: spi-pins-1 { + marvell,pins = "mpp56", "mpp57", "mpp58", + "mpp59"; + marvell,function = "spi1"; + }; + + uart0_pins: uart-pins-0 { + marvell,pins = "mpp0", "mpp1"; + marvell,function = "ua0"; + }; + + uart1_pins: uart-pins-1 { + marvell,pins = "mpp19", "mpp20"; + marvell,function = "ua1"; + }; + + sdhci_pins: sdhci-pins { + marvell,pins = "mpp48", "mpp49", "mpp50", + "mpp52", "mpp53", "mpp54", + "mpp55", "mpp57", "mpp58", + "mpp59"; + marvell,function = "sd0"; + }; + + sata0_pins: sata-pins-0 { + marvell,pins = "mpp20"; + marvell,function = "sata0"; + }; + + sata1_pins: sata-pins-1 { + marvell,pins = "mpp19"; + marvell,function = "sata1"; + }; + + sata2_pins: sata-pins-2 { + marvell,pins = "mpp47"; + marvell,function = "sata2"; + }; + + sata3_pins: sata-pins-3 { + marvell,pins = "mpp44"; + marvell,function = "sata3"; + }; + }; + + gpio0: gpio@18100 { + compatible = "marvell,orion-gpio"; + reg = <0x18100 0x40>; + ngpios = <32>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + , + ; + }; + + gpio1: gpio@18140 { + compatible = "marvell,orion-gpio"; + reg = <0x18140 0x40>; + ngpios = <28>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + , + ; + }; + + system-controller@18200 { + compatible = "marvell,armada-380-system-controller", + "marvell,armada-370-xp-system-controller"; + reg = <0x18200 0x100>; + }; + + gateclk: clock-gating-control@18220 { + compatible = "marvell,armada-380-gating-clock"; + reg = <0x18220 0x4>; + clocks = <&coreclk 0>; + #clock-cells = <1>; + }; + + coreclk: mvebu-sar@18600 { + compatible = "marvell,armada-380-core-clock"; + reg = <0x18600 0x04>; + #clock-cells = <1>; + }; + + mbusc: mbus-controller@20000 { + compatible = "marvell,mbus-controller"; + reg = <0x20000 0x100>, <0x20180 0x20>; + }; + + mpic: interrupt-controller@20a00 { + compatible = "marvell,mpic"; + reg = <0x20a00 0x2d0>, <0x21070 0x58>; + #interrupt-cells = <1>; + #size-cells = <1>; + interrupt-controller; + msi-controller; + interrupts = ; + }; + + timer@20300 { + compatible = "marvell,armada-380-timer", + "marvell,armada-xp-timer"; + reg = <0x20300 0x30>, <0x21040 0x30>; + interrupts-extended = <&gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, + <&mpic 5>, + <&mpic 6>; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; + }; + + watchdog@20300 { + compatible = "marvell,armada-380-wdt"; + reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; + }; + + cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x10>; + }; + + mpcore-soc-ctrl@20d20 { + compatible = "marvell,armada-380-mpcore-soc-ctrl"; + reg = <0x20d20 0x6c>; + }; + + coherency-fabric@21010 { + compatible = "marvell,armada-380-coherency-fabric"; + reg = <0x21010 0x1c>; + }; + + pmsu@22000 { + compatible = "marvell,armada-380-pmsu"; + reg = <0x22000 0x1000>; + }; + + eth1: ethernet@30000 { + compatible = "marvell,armada-370-neta"; + reg = <0x30000 0x4000>; + interrupts-extended = <&mpic 10>; + clocks = <&gateclk 3>; + status = "disabled"; + }; + + eth2: ethernet@34000 { + compatible = "marvell,armada-370-neta"; + reg = <0x34000 0x4000>; + interrupts-extended = <&mpic 12>; + clocks = <&gateclk 2>; + status = "disabled"; + }; + + usb@58000 { + compatible = "marvell,orion-ehci"; + reg = <0x58000 0x500>; + interrupts = ; + clocks = <&gateclk 18>; + status = "disabled"; + }; + + xor@60800 { + compatible = "marvell,orion-xor"; + reg = <0x60800 0x100 + 0x60a00 0x100>; + clocks = <&gateclk 22>; + status = "okay"; + + xor00 { + interrupts = ; + dmacap,memcpy; + dmacap,xor; + }; + xor01 { + interrupts = ; + dmacap,memcpy; + dmacap,xor; + dmacap,memset; + }; + }; + + xor@60900 { + compatible = "marvell,orion-xor"; + reg = <0x60900 0x100 + 0x60b00 0x100>; + clocks = <&gateclk 28>; + status = "okay"; + + xor10 { + interrupts = ; + dmacap,memcpy; + dmacap,xor; + }; + xor11 { + interrupts = ; + dmacap,memcpy; + dmacap,xor; + dmacap,memset; + }; + }; + + eth0: ethernet@70000 { + compatible = "marvell,armada-370-neta"; + reg = <0x70000 0x4000>; + interrupts-extended = <&mpic 8>; + clocks = <&gateclk 4>; + status = "disabled"; + }; + + mdio: mdio@72004 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0x72004 0x4>; + clocks = <&gateclk 4>; + }; + + rtc@a3800 { + compatible = "marvell,armada-380-rtc"; + reg = <0xa3800 0x20>, <0x184a0 0x0c>; + reg-names = "rtc", "rtc-soc"; + interrupts = ; + }; + + sata@a8000 { + compatible = "marvell,armada-380-ahci"; + reg = <0xa8000 0x2000>; + interrupts = ; + clocks = <&gateclk 15>; + status = "disabled"; + }; + + sata@e0000 { + compatible = "marvell,armada-380-ahci"; + reg = <0xe0000 0x2000>; + interrupts = ; + clocks = <&gateclk 30>; + status = "disabled"; + }; + + coredivclk: clock@e4250 { + compatible = "marvell,armada-380-corediv-clock"; + reg = <0xe4250 0xc>; + #clock-cells = <1>; + clocks = <&mainpll>; + clock-output-names = "nand"; + }; + + thermal@e8078 { + compatible = "marvell,armada380-thermal"; + reg = <0xe4078 0x4>, <0xe4074 0x4>; + status = "okay"; + }; + + flash@d0000 { + compatible = "marvell,armada370-nand"; + reg = <0xd0000 0x54>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = ; + clocks = <&coredivclk 0>; + status = "disabled"; + }; + + sdhci@d8000 { + compatible = "marvell,armada-380-sdhci"; + reg-names = "sdhci", "mbus", "conf-sdio3"; + reg = <0xd8000 0x1000>, + <0xdc000 0x100>, + <0x18454 0x4>; + interrupts = ; + clocks = <&gateclk 17>; + mrvl,clk-delay-cycles = <0x1F>; + status = "disabled"; + }; + + usb3@f0000 { + compatible = "marvell,armada-380-xhci"; + reg = <0xf0000 0x4000>,<0xf4000 0x4000>; + interrupts = ; + clocks = <&gateclk 9>; + status = "disabled"; + }; + + usb3@f8000 { + compatible = "marvell,armada-380-xhci"; + reg = <0xf8000 0x4000>,<0xfc000 0x4000>; + interrupts = ; + clocks = <&gateclk 10>; + status = "disabled"; + }; + }; + }; + + pci0: pcie@f1080000 { + compatible = "mrvl,pcie"; + status = "disabled"; + device_type = "pci"; + #interrupt-cells = <3>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xf1080000 0x2000>; + bus-range = <0 255>; + ranges = <0x42000000 0x0 0xf1200000 0xf1200000 0x0 0x00100000 + 0x41000000 0x0 0x00000000 0xf1300000 0x0 0x00100000>; + interrupt-parent = <&gic>; + interrupts = ; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + 0x0000 0x0 0x0 0x1 &gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH + >; + }; + + clocks { + /* 2 GHz fixed main PLL */ + mainpll: mainpll { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + }; + + /* 25 MHz reference crystal */ + refclk: oscillator { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + }; +}; Property changes on: projects/release-pkg/sys/boot/fdt/dts/arm/armada-38x.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sys/boot/fdt/dts/arm/db78460.dts =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/db78460.dts (revision 294447) +++ projects/release-pkg/sys/boot/fdt/dts/arm/db78460.dts (revision 294448) @@ -1,327 +1,323 @@ /* * Copyright (c) 2010 The FreeBSD Foundation * Copyright (c) 2010-2011 Semihalf * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Marvell DB-78460 Device Tree Source. * * $FreeBSD$ */ /dts-v1/; / { model = "mrvl,DB-78460"; #address-cells = <1>; #size-cells = <1>; aliases { serial0 = &serial0; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "ARM,88VS584"; reg = <0x0>; d-cache-line-size = <32>; // 32 bytes i-cache-line-size = <32>; // 32 bytes d-cache-size = <0x8000>; // L1, 32K i-cache-size = <0x8000>; // L1, 32K timebase-frequency = <0>; bus-frequency = <200000000>; clock-frequency = <0>; }; }; memory { device_type = "memory"; reg = <0x0 0x80000000>; // 2G at 0x0 }; soc78460@d0000000 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges = <0x0 0xd0000000 0x00100000>; bus-frequency = <0>; MPIC: mpic@20a00 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; reg = <0x20a00 0x500 0x21000 0x800 0x20400 0x100>; compatible = "mrvl,mpic"; }; rtc@10300 { compatible = "mrvl,rtc"; reg = <0x10300 0x08>; }; timer@21840 { compatible = "mrvl,timer"; reg = <0x21840 0x30>; interrupts = <5>; interrupt-parent = <&MPIC>; mrvl,has-wdt; }; twsi@11000 { #address-cells = <1>; #size-cells = <0>; compatible = "mrvl,twsi"; reg = <0x11000 0x20>; interrupts = <31>; interrupt-parent = <&MPIC>; }; twsi@11100 { #address-cells = <1>; #size-cells = <0>; compatible = "mrvl,twsi"; reg = <0x11100 0x20>; interrupts = <32>; interrupt-parent = <&MPIC>; }; serial0: serial@12000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x12000 0x20>; reg-shift = <2>; current-speed = <115200>; clock-frequency = <0>; - busy-detect = <1>; interrupts = <41>; interrupt-parent = <&MPIC>; }; serial1: serial@12100 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x12100 0x20>; reg-shift = <2>; current-speed = <115200>; clock-frequency = <0>; - busy-detect = <1>; interrupts = <42>; interrupt-parent = <&MPIC>; }; serial2: serial@12200 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x12200 0x20>; reg-shift = <2>; current-speed = <115200>; clock-frequency = <0>; - busy-detect = <1>; interrupts = <43>; interrupt-parent = <&MPIC>; }; serial3: serial@12300 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x12300 0x20>; reg-shift = <2>; current-speed = <115200>; clock-frequency = <0>; - busy-detect = <1>; interrupts = <44>; interrupt-parent = <&MPIC>; }; MPP: mpp@10000 { #pin-cells = <2>; compatible = "mrvl,mpp"; reg = <0x18000 0x34>; pin-count = <68>; pin-map = < 0 1 /* MPP[0]: GE1_TXCLK */ 1 1 /* MPP[1]: GE1_TXCTL */ 2 1 /* MPP[2]: GE1_RXCTL */ 3 1 /* MPP[3]: GE1_RXCLK */ 4 1 /* MPP[4]: GE1_TXD[0] */ 5 1 /* MPP[5]: GE1_TXD[1] */ 6 1 /* MPP[6]: GE1_TXD[2] */ 7 1 /* MPP[7]: GE1_TXD[3] */ 8 1 /* MPP[8]: GE1_RXD[0] */ 9 1 /* MPP[9]: GE1_RXD[1] */ 10 1 /* MPP[10]: GE1_RXD[2] */ 11 1 /* MPP[11]: GE1_RXD[3] */ 12 2 /* MPP[13]: SYSRST_OUTn */ 13 2 /* MPP[13]: SYSRST_OUTn */ 14 2 /* MPP[14]: SATA1_ACTn */ 15 2 /* MPP[15]: SATA0_ACTn */ 16 2 /* MPP[16]: UA2_TXD */ 17 2 /* MPP[17]: UA2_RXD */ 18 2 /* MPP[18]: */ 19 2 /* MPP[19]: */ 20 2 /* MPP[20]: */ 21 2 /* MPP[21]: */ 22 2 /* MPP[22]: UA3_TXD */ 23 2 24 0 25 0 26 0 27 0 28 4 29 0 30 1 31 1 32 1 33 1 34 1 35 1 36 1 37 1 38 1 39 1 40 0 41 3 42 1 43 1 44 2 45 2 46 4 47 3 48 0 49 1 50 1 51 1 52 1 53 1 54 1 55 1 56 1 57 0 58 1 59 1 60 1 61 1 62 1 63 1 64 1 65 1 66 1 67 2 >; }; usb@50000 { compatible = "mrvl,usb-ehci", "usb-ehci"; reg = <0x50000 0x1000>; interrupts = <124 45>; interrupt-parent = <&MPIC>; }; usb@51000 { compatible = "mrvl,usb-ehci", "usb-ehci"; reg = <0x51000 0x1000>; interrupts = <124 46>; interrupt-parent = <&MPIC>; }; usb@52000 { compatible = "mrvl,usb-ehci", "usb-ehci"; reg = <0x52000 0x1000>; interrupts = <124 47>; interrupt-parent = <&MPIC>; }; enet0: ethernet@72000 { #address-cells = <1>; #size-cells = <1>; model = "V2"; compatible = "mrvl,ge"; reg = <0x72000 0x2000>; ranges = <0x0 0x72000 0x2000>; local-mac-address = [ 00 04 01 07 84 60 ]; interrupts = <67 68 122 >; interrupt-parent = <&MPIC>; phy-handle = <&phy0>; has-neta; mdio@0 { #address-cells = <1>; #size-cells = <0>; compatible = "mrvl,mdio"; phy0: ethernet-phy@0 { reg = <0x0>; }; phy1: ethernet-phy@1 { reg = <0x1>; }; phy2: ethernet-phy@2 { reg = <0x19>; }; phy3: ethernet-phy@3 { reg = <0x1b>; }; }; }; sata@A0000 { compatible = "mrvl,sata"; reg = <0xA0000 0x6000>; interrupts = <55>; interrupt-parent = <&MPIC>; }; }; pci0: pcie@d0040000 { compatible = "mrvl,pcie"; device_type = "pci"; #interrupt-cells = <1>; #size-cells = <2>; #address-cells = <3>; reg = <0xd0040000 0x2000>; bus-range = <0 255>; ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x20000000 0x01000000 0x0 0x00000000 0xa0000000 0x0 0x08000000>; clock-frequency = <33333333>; interrupt-parent = <&MPIC>; interrupts = <120>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < 0x0800 0x0 0x0 0x1 &MPIC 0x3A 0x0800 0x0 0x0 0x2 &MPIC 0x3A 0x0800 0x0 0x0 0x3 &MPIC 0x3A 0x0800 0x0 0x0 0x4 &MPIC 0x3A >; }; sram@ffff0000 { compatible = "mrvl,cesa-sram"; reg = <0xffff0000 0x00010000>; }; chosen { stdin = "serial0"; stdout = "serial0"; stddbg = "serial0"; }; }; Index: projects/release-pkg/sys/boot/fdt/dts/arm/rk3188.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/rk3188.dtsi (revision 294447) +++ projects/release-pkg/sys/boot/fdt/dts/arm/rk3188.dtsi (revision 294448) @@ -1,258 +1,254 @@ /*- * Copyright (c) 2013 Ganbold Tsagaankhuu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ / { compatible = "rockchip,rk3188"; #address-cells = <1>; #size-cells = <1>; interrupt-parent = <&GIC>; aliases { soc = &SOC; }; SOC: rk3188 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges; bus-frequency = <0>; GIC: interrupt-controller@1013d000 { compatible = "arm,gic"; reg = <0x1013d000 0x1000>, /* Distributor Registers */ <0x1013c100 0x0100>; /* CPU Interface Registers */ interrupt-controller; #interrupt-cells = <1>; }; pmu@20004000 { compatible = "rockchip,rk30xx-pmu"; #address-cells = <1>; #size-cells = <1>; reg = <0x20004000 0x100>; }; grf@20008000 { compatible = "rockchip,rk30xx-grf"; #address-cells = <1>; #size-cells = <1>; reg = < 0x20008000 0x2000 >; }; mp_tmr@1013c600 { compatible = "arm,mpcore-timers"; #address-cells = <1>; #size-cells = <0>; clock-frequency = < 148500000 >; reg = <0x1013c200 0x100>, /* Global Timer Regs */ <0x1013c600 0x20>; /* Private Timer Regs */ interrupts = < 27 29 >; interrupt-parent = <&GIC>; }; timer@20038000 { compatible = "rockchip,rk30xx-timer"; reg = <0x20038000 0x20>; interrupts = <76>; clock-frequency = <24000000>; status = "disabled"; }; timer@20038020 { compatible = "rockchip,rk30xx-timer"; reg = <0x20038020 0x20>; interrupts = <77>; clock-frequency = <24000000>; status = "disabled"; }; timer@20038060 { compatible = "rockchip,rk30xx-timer"; reg = <0x20038060 0x20>; interrupts = <91>; clock-frequency = <24000000>; status = "disabled"; }; timer@20038080 { compatible = "rockchip,rk30xx-timer"; reg = <0x20038080 0x20>; interrupts = <92>; clock-frequency = <24000000>; status = "disabled"; }; timer@200380a0 { compatible = "rockchip,rk30xx-timer"; reg = <0x200380a0 0x20>; interrupts = <96>; clock-frequency = <24000000>; status = "disabled"; }; watchdog@2004c000 { compatible = "rockchip,rk30xx-wdt"; reg = <0x2004c000 0x100>; clock-frequency = < 66000000 >; }; gpio0: gpio@2000a000 { compatible = "rockchip,rk30xx-gpio"; gpio-controller; #gpio-cells = <2>; reg = <0x2000a000 0x100>; interrupts = <86>; interrupt-parent = <&GIC>; }; gpio1: gpio@2003c000 { compatible = "rockchip,rk30xx-gpio"; gpio-controller; #gpio-cells = <2>; reg = <0x2003c000 0x100>; interrupts = <87>; interrupt-parent = <&GIC>; }; gpio2: gpio@2003e000 { compatible = "rockchip,rk30xx-gpio"; gpio-controller; #gpio-cells = <2>; reg = <0x2003e000 0x100>; interrupts = <88>; interrupt-parent = <&GIC>; }; gpio3: gpio@20080000 { compatible = "rockchip,rk30xx-gpio"; gpio-controller; #gpio-cells = <2>; reg = <0x20080000 0x100>; interrupts = <89>; interrupt-parent = <&GIC>; }; usb0: usb@10180000 { compatible = "synopsys,designware-hs-otg2"; reg = <0x10180000 0x40000>; interrupts = <48>; interrupt-parent = <&GIC>; #address-cells = <1>; #size-cells = <0>; }; usb1: usb@101c0000 { compatible = "synopsys,designware-hs-otg2"; reg = <0x101c0000 0x40000>; interrupts = < 49 >; interrupt-parent = <&GIC>; #address-cells = <1>; #size-cells = <0>; gpios = <&gpio0 3 2 2>; }; uart0: serial@10124000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x10124000 0x400>; reg-shift = <2>; interrupts = <66>; interrupt-parent = <&GIC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; broken-txfifo = <1>; status = "disabled"; }; uart1: serial@10126000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x10126000 0x400>; reg-shift = <2>; interrupts = <67>; interrupt-parent = <&GIC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; broken-txfifo = <1>; status = "disabled"; }; uart2: serial@20064000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x20064000 0x400>; reg-shift = <2>; interrupts = <68>; interrupt-parent = <&GIC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; broken-txfifo = <1>; status = "disabled"; }; uart3: serial@20068000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x20068000 0x400>; reg-shift = <2>; interrupts = <69>; interrupt-parent = <&GIC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; broken-txfifo = <1>; status = "disabled"; }; mmc@10214000 { compatible = "rockchip,rk2928-dw-mshc"; reg = <0x10214000 0x1000>; interrupts = <55>; #address-cells = <1>; #size-cells = <0>; bus-frequency = <48000000>; /* TODO: verify freq */ fifo-depth = <0x40>; num-slots = <1>; status = "disabled"; }; mmc@10218000 { compatible = "rockchip,rk2928-dw-mshc"; reg = <0x10218000 0x1000>; interrupts = <56>; #address-cells = <1>; #size-cells = <0>; bus-frequency = <48000000>; /* TODO: verify freq */ fifo-depth = <0x40>; num-slots = <1>; status = "disabled"; }; }; }; Index: projects/release-pkg/sys/boot/fdt/dts/arm/sun4i-a10.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/sun4i-a10.dtsi (revision 294447) +++ projects/release-pkg/sys/boot/fdt/dts/arm/sun4i-a10.dtsi (revision 294448) @@ -1,141 +1,140 @@ /*- * Copyright (c) 2014 Ganbold Tsagaankhuu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ / { compatible = "allwinner,sun4i-a10"; #address-cells = <1>; #size-cells = <1>; interrupt-parent = <&AINTC>; aliases { soc = &SOC; }; SOC: a10 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges; bus-frequency = <0>; AINTC: interrupt-controller@01c20400 { compatible = "allwinner,sun4i-ic"; interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; reg = < 0x01c20400 0x400 >; }; sramc@01c00000 { compatible = "allwinner,sun4i-sramc"; #address-cells = <1>; #size-cells = <1>; reg = < 0x01c00000 0x1000 >; }; ccm@01c20000 { compatible = "allwinner,sun4i-ccm"; #address-cells = <1>; #size-cells = <1>; reg = < 0x01c20000 0x400 >; }; timer@01c20c00 { compatible = "allwinner,sun4i-timer"; reg = <0x01c20c00 0x90>; interrupts = < 22 >; interrupt-parent = <&AINTC>; clock-frequency = < 24000000 >; }; watchdog@01c20c90 { compatible = "allwinner,sun4i-wdt"; reg = <0x01c20c90 0x08>; }; GPIO: gpio@01c20800 { #gpio-cells = <3>; compatible = "allwinner,sun4i-gpio"; gpio-controller; reg =< 0x01c20800 0x400 >; interrupts = < 28 >; interrupt-parent = <&AINTC>; }; usb1: usb@01c14000 { compatible = "allwinner,usb-ehci", "usb-ehci"; reg = <0x01c14000 0x1000>; interrupts = < 39 >; interrupt-parent = <&AINTC>; }; usb2: usb@01c1c000 { compatible = "allwinner,usb-ehci", "usb-ehci"; reg = <0x01c1c000 0x1000>; interrupts = < 40 >; interrupt-parent = <&AINTC>; }; mmc0: mmc@01c0f000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c0f000 0x1000>; interrupts = <32>; interrupt-parent = <&AINTC>; status = "disabled"; }; sata@01c18000 { compatible = "allwinner,sun4i-a10-ahci"; reg = <0x01c18000 0x1000>; interrupts = <56>; interrupt-parent = <&AINTC>; status = "disabled"; }; UART0: serial@01c28000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; reg-shift = <2>; interrupts = <1>; interrupt-parent = <&AINTC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; }; emac@01c0b000 { compatible = "allwinner,sun4i-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; interrupt-parent = <&AINTC>; }; }; }; Index: projects/release-pkg/sys/boot/fdt/dts/arm/sun7i-a20.dtsi =================================================================== --- projects/release-pkg/sys/boot/fdt/dts/arm/sun7i-a20.dtsi (revision 294447) +++ projects/release-pkg/sys/boot/fdt/dts/arm/sun7i-a20.dtsi (revision 294448) @@ -1,161 +1,160 @@ /*- * Copyright (c) 2014 Ganbold Tsagaankhuu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ / { compatible = "allwinner,sun7i-a20"; #address-cells = <1>; #size-cells = <1>; interrupt-parent = <&GIC>; aliases { soc = &SOC; }; SOC: a20 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges; bus-frequency = <0>; GIC: interrupt-controller@01c81000 { compatible = "arm,gic"; reg = <0x01c81000 0x1000>, /* Distributor Registers */ <0x01c82000 0x0100>; /* CPU Interface Registers */ interrupt-controller; #interrupt-cells = <1>; }; sramc@01c00000 { compatible = "allwinner,sun4i-sramc"; #address-cells = <1>; #size-cells = <1>; reg = < 0x01c00000 0x1000 >; }; cpu-cfg@01c25c00 { compatible = "allwinner,sun7i-cpu-cfg"; #address-cells = <1>; #size-cells = <1>; reg = < 0x01c25c00 0x400 >; }; ccm@01c20000 { compatible = "allwinner,sun4i-ccm"; #address-cells = <1>; #size-cells = <1>; reg = < 0x01c20000 0x400 >; }; timer@01c20c00 { compatible = "allwinner,sun7i-timer"; reg = <0x01c20c00 0x90>; interrupts = < 22 >; interrupt-parent = <&GIC>; clock-frequency = < 24000000 >; }; watchdog@01c20c90 { compatible = "allwinner,sun4i-wdt"; reg = <0x01c20c90 0x10>; }; pio: gpio@01c20800 { #gpio-cells = <3>; compatible = "allwinner,sun4i-gpio"; gpio-controller; reg =< 0x01c20800 0x400 >; interrupts = < 28 >; interrupt-parent = <&GIC>; }; usb1: usb@01c14000 { compatible = "allwinner,usb-ehci", "usb-ehci"; reg = <0x01c14000 0x1000>; interrupts = < 39 >; interrupt-parent = <&GIC>; }; usb2: usb@01c1c000 { compatible = "allwinner,usb-ehci", "usb-ehci"; reg = <0x01c1c000 0x1000>; interrupts = < 40 >; interrupt-parent = <&GIC>; }; mmc0: mmc@01c0f000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c0f000 0x1000>; interrupts = <32>; interrupt-parent = <&GIC>; status = "disabled"; }; sata@01c18000 { compatible = "allwinner,sun4i-a10-ahci"; reg = <0x01c18000 0x1000>; interrupts = <56>; interrupt-parent = <&GIC>; status = "disabled"; }; UART0: serial@01c28000 { - compatible = "ns16550"; + compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; reg-shift = <2>; interrupts = <1>; interrupt-parent = <&GIC>; current-speed = <115200>; clock-frequency = < 24000000 >; - busy-detect = <1>; }; emac@01c0b000 { compatible = "allwinner,sun4i-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; interrupt-parent = <&GIC>; status = "disabled"; }; gmac@01c50000 { compatible = "allwinner,sun7i-a20-gmac"; reg = <0x01c50000 0x10000>; interrupts = <85>; interrupt-parent = <&GIC>; snps,pbl = <2>; snps,fixed-burst; snps,force_sf_dma_mode; status = "disabled"; #address-cells = <1>; #size-cells = <0>; }; }; }; Index: projects/release-pkg/sys/boot =================================================================== --- projects/release-pkg/sys/boot (revision 294447) +++ projects/release-pkg/sys/boot (revision 294448) Property changes on: projects/release-pkg/sys/boot ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/boot:r294408-294447 Index: projects/release-pkg/sys/conf/options.arm =================================================================== --- projects/release-pkg/sys/conf/options.arm (revision 294447) +++ projects/release-pkg/sys/conf/options.arm (revision 294448) @@ -1,73 +1,74 @@ #$FreeBSD$ ARMV6 opt_global.h ARM_CACHE_LOCK_ENABLE opt_global.h ARM_INTRNG opt_global.h ARM_KERN_DIRECTMAP opt_vm.h ARM_L2_PIPT opt_global.h ARM_MANY_BOARD opt_global.h ARM_NEW_PMAP opt_global.h NKPT2PG opt_pmap.h ARM_WANT_TP_ADDRESS opt_global.h COUNTS_PER_SEC opt_timer.h CPU_ARM9 opt_global.h CPU_ARM9E opt_global.h CPU_ARM1176 opt_global.h CPU_CORTEXA opt_global.h CPU_KRAIT opt_global.h CPU_FA526 opt_global.h CPU_MV_PJ4B opt_global.h CPU_XSCALE_80219 opt_global.h CPU_XSCALE_80321 opt_global.h CPU_XSCALE_81342 opt_global.h CPU_XSCALE_IXP425 opt_global.h CPU_XSCALE_IXP435 opt_global.h CPU_XSCALE_PXA2X0 opt_global.h DEV_GIC opt_global.h DEV_PMU opt_global.h EFI opt_platform.h FLASHADDR opt_global.h GIC_DEFAULT_ICFGR_INIT opt_global.h IPI_IRQ_START opt_smp.h IPI_IRQ_END opt_smp.h FREEBSD_BOOT_LOADER opt_global.h IXP4XX_FLASH_SIZE opt_global.h KERNBASE opt_global.h KERNVIRTADDR opt_global.h LINUX_BOOT_ABI opt_global.h LOADERRAMADDR opt_global.h PHYSADDR opt_global.h PLATFORM opt_global.h SOCDEV_PA opt_global.h SOCDEV_VA opt_global.h PV_STATS opt_pmap.h QEMU_WORKAROUNDS opt_global.h SOC_BCM2835 opt_global.h SOC_BCM2836 opt_global.h SOC_IMX51 opt_global.h SOC_IMX53 opt_global.h SOC_IMX6 opt_global.h SOC_MV_ARMADAXP opt_global.h +SOC_MV_ARMADA38X opt_global.h SOC_MV_DISCOVERY opt_global.h SOC_MV_DOVE opt_global.h SOC_MV_FREY opt_global.h SOC_MV_KIRKWOOD opt_global.h SOC_MV_LOKIPLUS opt_global.h SOC_MV_ORION opt_global.h SOC_OMAP3 opt_global.h SOC_OMAP4 opt_global.h SOC_TI_AM335X opt_global.h SOC_TEGRA2 opt_global.h XSCALE_CACHE_READ_WRITE_ALLOCATE opt_global.h XSACLE_DISABLE_CCNT opt_timer.h VERBOSE_INIT_ARM opt_global.h VM_MAXUSER_ADDRESS opt_global.h AT91_ATE_USE_RMII opt_at91.h AT91_MACB_USE_RMII opt_at91.h AT91_MCI_ALLOW_OVERCLOCK opt_at91.h AT91_MCI_HAS_4WIRE opt_at91.h AT91_MCI_SLOT_B opt_at91.h GFB_DEBUG opt_gfb.h GFB_NO_FONT_LOADING opt_gfb.h GFB_NO_MODE_CHANGE opt_gfb.h AT91C_MAIN_CLOCK opt_at91.h VFP opt_global.h Index: projects/release-pkg/sys/conf =================================================================== --- projects/release-pkg/sys/conf (revision 294447) +++ projects/release-pkg/sys/conf (revision 294448) Property changes on: projects/release-pkg/sys/conf ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/conf:r294408-294447 Index: projects/release-pkg/sys/dev/fdt/fdt_common.c =================================================================== --- projects/release-pkg/sys/dev/fdt/fdt_common.c (revision 294447) +++ projects/release-pkg/sys/dev/fdt/fdt_common.c (revision 294448) @@ -1,723 +1,723 @@ /*- * Copyright (c) 2009-2014 The FreeBSD Foundation * All rights reserved. * * This software was developed by Andrew Turner under sponsorship from * the FreeBSD Foundation. * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "ofw_bus_if.h" #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif #define FDT_COMPAT_LEN 255 #define FDT_TYPE_LEN 64 #define FDT_REG_CELLS 4 vm_paddr_t fdt_immr_pa; vm_offset_t fdt_immr_va; vm_offset_t fdt_immr_size; struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); static int fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base, u_long *size) { pcell_t ranges[32], *rangesptr; pcell_t addr_cells, size_cells, par_addr_cells; u_long bus_addr, par_bus_addr, pbase, psize; int err, i, len, tuple_size, tuples; if (node == 0) { *base = 0; *size = ULONG_MAX; return (0); } if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) return (ENXIO); /* * Process 'ranges' property. */ par_addr_cells = fdt_parent_addr_cells(node); if (par_addr_cells > 2) { return (ERANGE); } len = OF_getproplen(node, "ranges"); if (len < 0) return (-1); if (len > sizeof(ranges)) return (ENOMEM); if (len == 0) { return (fdt_get_range_by_busaddr(OF_parent(node), addr, base, size)); } if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) return (EINVAL); tuple_size = addr_cells + par_addr_cells + size_cells; tuples = len / (tuple_size * sizeof(cell_t)); if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) return (ERANGE); *base = 0; *size = 0; for (i = 0; i < tuples; i++) { rangesptr = &ranges[i * tuple_size]; bus_addr = fdt_data_get((void *)rangesptr, addr_cells); if (bus_addr != addr) continue; rangesptr += addr_cells; par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells); rangesptr += par_addr_cells; err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr, &pbase, &psize); if (err > 0) return (err); if (err == 0) *base = pbase; else *base = par_bus_addr; *size = fdt_data_get((void *)rangesptr, size_cells); return (0); } return (EINVAL); } int fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) { pcell_t ranges[6], *rangesptr; pcell_t addr_cells, size_cells, par_addr_cells; u_long par_bus_addr, pbase, psize; int err, len, tuple_size, tuples; if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) return (ENXIO); /* * Process 'ranges' property. */ par_addr_cells = fdt_parent_addr_cells(node); if (par_addr_cells > 2) return (ERANGE); len = OF_getproplen(node, "ranges"); if (len > sizeof(ranges)) return (ENOMEM); if (len == 0) { *base = 0; *size = ULONG_MAX; return (0); } if (!(range_id < len)) return (ERANGE); if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) return (EINVAL); tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + size_cells); tuples = len / tuple_size; if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) return (ERANGE); *base = 0; *size = 0; rangesptr = &ranges[range_id]; *base = fdt_data_get((void *)rangesptr, addr_cells); rangesptr += addr_cells; par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells); rangesptr += par_addr_cells; err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr, &pbase, &psize); if (err == 0) *base += pbase; else *base += par_bus_addr; *size = fdt_data_get((void *)rangesptr, size_cells); return (0); } int fdt_immr_addr(vm_offset_t immr_va) { phandle_t node; u_long base, size; int r; /* * Try to access the SOC node directly i.e. through /aliases/. */ if ((node = OF_finddevice("soc")) != 0) - if (fdt_is_compatible_strict(node, "simple-bus")) + if (fdt_is_compatible(node, "simple-bus")) goto moveon; /* * Find the node the long way. */ if ((node = OF_finddevice("/")) == 0) return (ENXIO); - if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) + if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0) return (ENXIO); moveon: if ((r = fdt_get_range(node, 0, &base, &size)) == 0) { fdt_immr_pa = base; fdt_immr_va = immr_va; fdt_immr_size = size; } return (r); } /* * This routine is an early-usage version of the ofw_bus_is_compatible() when * the ofw_bus I/F is not available (like early console routines and similar). * Note the buffer has to be on the stack since malloc() is usually not * available in such cases either. */ int fdt_is_compatible(phandle_t node, const char *compatstr) { char buf[FDT_COMPAT_LEN]; char *compat; int len, onelen, l, rv; if ((len = OF_getproplen(node, "compatible")) <= 0) return (0); compat = (char *)&buf; bzero(compat, FDT_COMPAT_LEN); if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) return (0); onelen = strlen(compatstr); rv = 0; while (len > 0) { if (strncasecmp(compat, compatstr, onelen) == 0) { /* Found it. */ rv = 1; break; } /* Slide to the next sub-string. */ l = strlen(compat) + 1; compat += l; len -= l; } return (rv); } int fdt_is_compatible_strict(phandle_t node, const char *compatible) { char compat[FDT_COMPAT_LEN]; if (OF_getproplen(node, "compatible") <= 0) return (0); if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) return (0); if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) /* This fits. */ return (1); return (0); } phandle_t fdt_find_compatible(phandle_t start, const char *compat, int strict) { phandle_t child; /* * Traverse all children of 'start' node, and find first with * matching 'compatible' property. */ for (child = OF_child(start); child != 0; child = OF_peer(child)) if (fdt_is_compatible(child, compat)) { if (strict) if (!fdt_is_compatible_strict(child, compat)) continue; return (child); } return (0); } phandle_t fdt_depth_search_compatible(phandle_t start, const char *compat, int strict) { phandle_t child, node; /* * Depth-search all descendants of 'start' node, and find first with * matching 'compatible' property. */ for (node = OF_child(start); node != 0; node = OF_peer(node)) { if (fdt_is_compatible(node, compat) && (strict == 0 || fdt_is_compatible_strict(node, compat))) { return (node); } child = fdt_depth_search_compatible(node, compat, strict); if (child != 0) return (child); } return (0); } int fdt_is_enabled(phandle_t node) { char *stat; int ena, len; len = OF_getprop_alloc(node, "status", sizeof(char), (void **)&stat); if (len <= 0) /* It is OK if no 'status' property. */ return (1); /* Anything other than 'okay' means disabled. */ ena = 0; if (strncmp((char *)stat, "okay", len) == 0) ena = 1; free(stat, M_OFWPROP); return (ena); } int fdt_is_type(phandle_t node, const char *typestr) { char type[FDT_TYPE_LEN]; if (OF_getproplen(node, "device_type") <= 0) return (0); if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) return (0); if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) /* This fits. */ return (1); return (0); } int fdt_parent_addr_cells(phandle_t node) { pcell_t addr_cells; /* Find out #address-cells of the superior bus. */ if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, sizeof(addr_cells)) <= 0) return (2); return ((int)fdt32_to_cpu(addr_cells)); } int fdt_pm_is_enabled(phandle_t node) { int ret; ret = 1; #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) ret = fdt_pm(node); #endif return (ret); } u_long fdt_data_get(void *data, int cells) { if (cells == 1) return (fdt32_to_cpu(*((uint32_t *)data))); return (fdt64_to_cpu(*((uint64_t *)data))); } int fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) { pcell_t cell; int cell_size; /* * Retrieve #{address,size}-cells. */ cell_size = sizeof(cell); if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) cell = 2; *addr_cells = fdt32_to_cpu((int)cell); if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size) cell = 1; *size_cells = fdt32_to_cpu((int)cell); if (*addr_cells > 3 || *size_cells > 2) return (ERANGE); return (0); } int fdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start, u_long *count) { /* Address portion. */ if (addr_cells > 2) return (ERANGE); *start = fdt_data_get((void *)data, addr_cells); data += addr_cells; /* Size portion. */ if (size_cells > 2) return (ERANGE); *count = fdt_data_get((void *)data, size_cells); return (0); } int fdt_regsize(phandle_t node, u_long *base, u_long *size) { pcell_t reg[4]; int addr_cells, len, size_cells; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) return (ENXIO); if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) return (ENOMEM); len = OF_getprop(node, "reg", ®, sizeof(reg)); if (len <= 0) return (EINVAL); *base = fdt_data_get(®[0], addr_cells); *size = fdt_data_get(®[addr_cells], size_cells); return (0); } int fdt_reg_to_rl(phandle_t node, struct resource_list *rl) { u_long end, count, start; pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; int i, rv; long busaddr, bussize; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { busaddr = 0; bussize = 0; } tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); if (tuples <= 0) /* No 'reg' property in this node. */ return (0); regptr = reg; for (i = 0; i < tuples; i++) { rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, &count); if (rv != 0) { resource_list_free(rl); goto out; } reg += addr_cells + size_cells; /* Calculate address range relative to base. */ start += busaddr; end = start + count - 1; debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, end, count); resource_list_add(rl, SYS_RES_MEMORY, i, start, end, count); } rv = 0; out: free(regptr, M_OFWPROP); return (rv); } int fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) { phandle_t phy_node; pcell_t phy_handle, phy_reg; uint32_t i; device_t parent, child; if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) <= 0) return (ENXIO); phy_node = OF_node_from_xref(phy_handle); if (OF_getprop(phy_node, "reg", (void *)&phy_reg, sizeof(phy_reg)) <= 0) return (ENXIO); *phy_addr = fdt32_to_cpu(phy_reg); /* * Search for softc used to communicate with phy. */ /* * Step 1: Search for ancestor of the phy-node with a "phy-handle" * property set. */ phy_node = OF_parent(phy_node); while (phy_node != 0) { if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) > 0) break; phy_node = OF_parent(phy_node); } if (phy_node == 0) return (ENXIO); /* * Step 2: For each device with the same parent and name as ours * compare its node with the one found in step 1, ancestor of phy * node (stored in phy_node). */ parent = device_get_parent(dev); i = 0; child = device_find_child(parent, device_get_name(dev), i); while (child != NULL) { if (ofw_bus_get_node(child) == phy_node) break; i++; child = device_find_child(parent, device_get_name(dev), i); } if (child == NULL) return (ENXIO); /* * Use softc of the device found. */ *phy_sc = (void *)device_get_softc(child); return (0); } int fdt_get_reserved_regions(struct mem_region *mr, int *mrcnt) { pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; pcell_t *reservep; phandle_t memory, root; uint32_t memory_size; int addr_cells, size_cells; int i, max_size, res_len, rv, tuple_size, tuples; max_size = sizeof(reserve); root = OF_finddevice("/"); memory = OF_finddevice("/memory"); if (memory == -1) { rv = ENXIO; goto out; } if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, &size_cells)) != 0) goto out; if (addr_cells > 2) { rv = ERANGE; goto out; } tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); res_len = OF_getproplen(root, "memreserve"); if (res_len <= 0 || res_len > sizeof(reserve)) { rv = ERANGE; goto out; } if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) { rv = ENXIO; goto out; } memory_size = 0; tuples = res_len / tuple_size; reservep = (pcell_t *)&reserve; for (i = 0; i < tuples; i++) { rv = fdt_data_to_res(reservep, addr_cells, size_cells, (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); if (rv != 0) goto out; reservep += addr_cells + size_cells; } *mrcnt = i; rv = 0; out: return (rv); } int fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) { pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; pcell_t *regp; phandle_t memory; uint32_t memory_size; int addr_cells, size_cells; int i, max_size, reg_len, rv, tuple_size, tuples; max_size = sizeof(reg); memory = OF_finddevice("/memory"); if (memory == -1) { rv = ENXIO; goto out; } if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, &size_cells)) != 0) goto out; if (addr_cells > 2) { rv = ERANGE; goto out; } tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); reg_len = OF_getproplen(memory, "reg"); if (reg_len <= 0 || reg_len > sizeof(reg)) { rv = ERANGE; goto out; } if (OF_getprop(memory, "reg", reg, reg_len) <= 0) { rv = ENXIO; goto out; } memory_size = 0; tuples = reg_len / tuple_size; regp = (pcell_t *)® for (i = 0; i < tuples; i++) { rv = fdt_data_to_res(regp, addr_cells, size_cells, (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); if (rv != 0) goto out; regp += addr_cells + size_cells; memory_size += mr[i].mr_size; } if (memory_size == 0) { rv = ERANGE; goto out; } *mrcnt = i; *memsize = memory_size; rv = 0; out: return (rv); } int fdt_get_unit(device_t dev) { const char * name; name = ofw_bus_get_name(dev); name = strchr(name, '@') + 1; return (strtol(name,NULL,0)); } Index: projects/release-pkg/sys/dev/ofw/ofw_bus_subr.c =================================================================== --- projects/release-pkg/sys/dev/ofw/ofw_bus_subr.c (revision 294447) +++ projects/release-pkg/sys/dev/ofw/ofw_bus_subr.c (revision 294448) @@ -1,754 +1,756 @@ /*- * Copyright (c) 2001 - 2003 by Thomas Moestl . * Copyright (c) 2005 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include "ofw_bus_if.h" int ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node) { if (obd == NULL) return (ENOMEM); /* The 'name' property is considered mandatory. */ if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1) return (EINVAL); OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat); OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type); OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model); OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status); obd->obd_node = node; return (0); } void ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd) { if (obd == NULL) return; if (obd->obd_compat != NULL) free(obd->obd_compat, M_OFWPROP); if (obd->obd_model != NULL) free(obd->obd_model, M_OFWPROP); if (obd->obd_name != NULL) free(obd->obd_name, M_OFWPROP); if (obd->obd_type != NULL) free(obd->obd_type, M_OFWPROP); if (obd->obd_status != NULL) free(obd->obd_status, M_OFWPROP); } int ofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf, size_t buflen) { if (ofw_bus_get_name(child) != NULL) { strlcat(buf, "name=", buflen); strlcat(buf, ofw_bus_get_name(child), buflen); } if (ofw_bus_get_compat(child) != NULL) { strlcat(buf, " compat=", buflen); strlcat(buf, ofw_bus_get_compat(child), buflen); } return (0); }; const char * ofw_bus_gen_get_compat(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_compat); } const char * ofw_bus_gen_get_model(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_model); } const char * ofw_bus_gen_get_name(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_name); } phandle_t ofw_bus_gen_get_node(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (0); return (obd->obd_node); } const char * ofw_bus_gen_get_type(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_type); } const char * ofw_bus_get_status(device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev); if (obd == NULL) return (NULL); return (obd->obd_status); } int ofw_bus_status_okay(device_t dev) { const char *status; status = ofw_bus_get_status(dev); if (status == NULL || strcmp(status, "okay") == 0 || strcmp(status, "ok") == 0) return (1); return (0); } static int ofw_bus_node_is_compatible(const char *compat, int len, const char *onecompat) { int onelen, l, ret; onelen = strlen(onecompat); ret = 0; while (len > 0) { if (strlen(compat) == onelen && strncasecmp(compat, onecompat, onelen) == 0) { /* Found it. */ ret = 1; break; } /* Slide to the next sub-string. */ l = strlen(compat) + 1; compat += l; len -= l; } return (ret); } int ofw_bus_is_compatible(device_t dev, const char *onecompat) { phandle_t node; const char *compat; int len; if ((compat = ofw_bus_get_compat(dev)) == NULL) return (0); if ((node = ofw_bus_get_node(dev)) == -1) return (0); /* Get total 'compatible' prop len */ if ((len = OF_getproplen(node, "compatible")) <= 0) return (0); return (ofw_bus_node_is_compatible(compat, len, onecompat)); } int ofw_bus_is_compatible_strict(device_t dev, const char *compatible) { const char *compat; size_t len; if ((compat = ofw_bus_get_compat(dev)) == NULL) return (0); len = strlen(compatible); if (strlen(compat) == len && strncasecmp(compat, compatible, len) == 0) return (1); return (0); } const struct ofw_compat_data * ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat) { if (compat == NULL) return NULL; for (; compat->ocd_str != NULL; ++compat) { if (ofw_bus_is_compatible(dev, compat->ocd_str)) break; } return (compat); } int ofw_bus_has_prop(device_t dev, const char *propname) { phandle_t node; if ((node = ofw_bus_get_node(dev)) == -1) return (0); return (OF_hasprop(node, propname)); } void ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) { pcell_t addrc; int msksz; if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) addrc = 2; ii->opi_addrc = addrc * sizeof(pcell_t); ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1, (void **)&ii->opi_imap); if (ii->opi_imapsz > 0) { msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1, (void **)&ii->opi_imapmsk); /* * Failure to get the mask is ignored; a full mask is used * then. We barf on bad mask sizes, however. */ if (msksz != -1 && msksz != ii->opi_addrc + intrsz) panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " "property!"); } } int ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, phandle_t *iparent) { uint8_t maskbuf[regsz + pintrsz]; int rv; if (ii->opi_imapsz <= 0) return (0); KASSERT(regsz >= ii->opi_addrc, ("ofw_bus_lookup_imap: register size too small: %d < %d", regsz, ii->opi_addrc)); if (node != -1) { rv = OF_getencprop(node, "reg", reg, regsz); if (rv < regsz) panic("ofw_bus_lookup_imap: cannot get reg property"); } return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc, ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr, mintrsz, iparent)); } /* * Map an interrupt using the firmware reg, interrupt-map and * interrupt-map-mask properties. * The interrupt property to be mapped must be of size intrsz, and pointed to * by intr. The regs property of the node for which the mapping is done must * be passed as regs. This property is an array of register specifications; * the size of the address part of such a specification must be passed as * physsz. Only the first element of the property is used. * imap and imapsz hold the interrupt mask and it's size. * imapmsk is a pointer to the interrupt-map-mask property, which must have * a size of physsz + intrsz; it may be NULL, in which case a full mask is * assumed. * maskbuf must point to a buffer of length physsz + intrsz. * The interrupt is returned in result, which must point to a buffer of length * rintrsz (which gives the expected size of the mapped interrupt). * Returns number of cells in the interrupt if a mapping was found, 0 otherwise. */ int ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, int rintrsz, phandle_t *iparent) { phandle_t parent; uint8_t *ref = maskbuf; uint8_t *uiintr = intr; uint8_t *uiregs = regs; uint8_t *uiimapmsk = imapmsk; uint8_t *mptr; pcell_t paddrsz; pcell_t pintrsz; int i, rsz, tsz; rsz = -1; if (imapmsk != NULL) { for (i = 0; i < physsz; i++) ref[i] = uiregs[i] & uiimapmsk[i]; for (i = 0; i < intrsz; i++) ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; } else { bcopy(regs, ref, physsz); bcopy(intr, ref + physsz, intrsz); } mptr = imap; i = imapsz; paddrsz = 0; while (i > 0) { bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); #ifndef OFW_IMAP_NO_IPARENT_ADDR_CELLS /* * Find if we need to read the parent address data. * CHRP-derived OF bindings, including ePAPR-compliant FDTs, * use this as an optional part of the specifier. */ if (OF_getencprop(OF_node_from_xref(parent), "#address-cells", &paddrsz, sizeof(paddrsz)) == -1) paddrsz = 0; /* default */ paddrsz *= sizeof(pcell_t); #endif if (OF_searchencprop(OF_node_from_xref(parent), "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1) pintrsz = 1; /* default */ pintrsz *= sizeof(pcell_t); /* Compute the map stride size. */ tsz = physsz + intrsz + sizeof(phandle_t) + paddrsz + pintrsz; KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); if (bcmp(ref, mptr, physsz + intrsz) == 0) { bcopy(mptr + physsz + intrsz + sizeof(parent) + paddrsz, result, MIN(rintrsz, pintrsz)); if (iparent != NULL) *iparent = parent; return (pintrsz/sizeof(pcell_t)); } mptr += tsz; i -= tsz; } return (0); } int ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl) { uint64_t phys, size; ssize_t i, j, rid, nreg, ret; uint32_t *reg; char *name; /* * This may be just redundant when having ofw_bus_devinfo * but makes this routine independent of it. */ ret = OF_getprop_alloc(node, "name", sizeof(*name), (void **)&name); if (ret == -1) name = NULL; ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); nreg = (ret == -1) ? 0 : ret; if (nreg % (acells + scells) != 0) { if (bootverbose) device_printf(dev, "Malformed reg property on <%s>\n", (name == NULL) ? "unknown" : name); nreg = 0; } for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) { phys = size = 0; for (j = 0; j < acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < scells; j++) { size <<= 32; size |= reg[i + acells + j]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(rl, SYS_RES_MEMORY, rid, phys, phys + size - 1, size); } free(name, M_OFWPROP); free(reg, M_OFWPROP); return (0); } /* * Get interrupt parent for given node. * Returns 0 if interrupt parent doesn't exist. */ phandle_t ofw_bus_find_iparent(phandle_t node) { phandle_t iparent; if (OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == -1) { for (iparent = node; iparent != 0; iparent = OF_parent(iparent)) { if (OF_hasprop(iparent, "interrupt-controller")) break; } iparent = OF_xref_from_node(iparent); } return (iparent); } int ofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl, int *rlen) { phandle_t iparent; uint32_t icells, *intr; int err, i, irqnum, nintr, rid; boolean_t extended; nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = ofw_bus_find_iparent(node); if (iparent == 0) { device_printf(dev, "No interrupt-parent found, " "assuming direct parent\n"); iparent = OF_parent(node); iparent = OF_xref_from_node(iparent); } if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells " "property, assuming <1>\n"); icells = 1; } if (icells < 1 || icells > nintr) { device_printf(dev, "Invalid #interrupt-cells property " "value <%d>, assuming <1>\n", icells); icells = 1; } extended = false; } else { nintr = OF_getencprop_alloc(node, "interrupts-extended", sizeof(*intr), (void **)&intr); if (nintr <= 0) return (0); extended = true; } err = 0; rid = 0; for (i = 0; i < nintr; i += icells) { if (extended) { iparent = intr[i++]; if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells " "property\n"); err = ENOENT; break; } if (icells < 1 || (i + icells) > nintr) { device_printf(dev, "Invalid #interrupt-cells " "property value <%d>\n", icells); err = ERANGE; break; } } irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1); } if (rlen != NULL) *rlen = rid; free(intr, M_OFWPROP); return (err); } phandle_t ofw_bus_find_child(phandle_t start, const char *child_name) { char *name; int ret; phandle_t child; for (child = OF_child(start); child != 0; child = OF_peer(child)) { ret = OF_getprop_alloc(child, "name", sizeof(*name), (void **)&name); if (ret == -1) continue; if (strcmp(name, child_name) == 0) { free(name, M_OFWPROP); return (child); } free(name, M_OFWPROP); } return (0); } phandle_t ofw_bus_find_compatible(phandle_t node, const char *onecompat) { phandle_t child, ret; void *compat; int len; /* * Traverse all children of 'start' node, and find first with * matching 'compatible' property. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { len = OF_getprop_alloc(child, "compatible", 1, &compat); if (len >= 0) { ret = ofw_bus_node_is_compatible(compat, len, onecompat); free(compat, M_OFWPROP); if (ret != 0) return (child); } ret = ofw_bus_find_compatible(child, onecompat); if (ret != 0) return (ret); } return (0); } /** * @brief Return child of bus whose phandle is node * * A direct child of @p will be returned if it its phandle in the * OFW tree is @p node. Otherwise, NULL is returned. * * @param bus The bus to examine * @param node The phandle_t to look for. */ device_t ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node) { device_t *children, retval, child; int nkid, i; /* * Nothing can match the flag value for no node. */ if (node == -1) return (NULL); /* * Search the children for a match. We microoptimize * a bit by not using ofw_bus_get since we already know * the parent. We do not recurse. */ if (device_get_children(bus, &children, &nkid) != 0) return (NULL); retval = NULL; for (i = 0; i < nkid; i++) { child = children[i]; if (OFW_BUS_GET_NODE(bus, child) == node) { retval = child; break; } } free(children, M_TEMP); return (retval); } /* * Parse property that contain list of xrefs and values * (like standard "clocks" and "resets" properties) * Input arguments: * node - consumers device node * list_name - name of parsed list - "clocks" * cells_name - name of size property - "#clock-cells" * Output arguments: * producer - handle of producer * ncells - number of cells in result * cells - array of decoded cells */ int ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name, const char *cells_name, int idx, phandle_t *producer, int *ncells, pcell_t **cells) { phandle_t pnode; phandle_t *elems; uint32_t pcells; int rv, i, j, nelems, cnt; elems = NULL; nelems = OF_getencprop_alloc(node, list_name, sizeof(*elems), (void **)&elems); if (nelems <= 0) return (ENOENT); rv = ENOENT; for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) { pnode = elems[i++]; if (OF_getencprop(OF_node_from_xref(pnode), cells_name, &pcells, sizeof(pcells)) == -1) { printf("Missing %s property\n", cells_name); rv = ENOENT; break; } if ((i + pcells) > nelems) { printf("Invalid %s property value <%d>\n", cells_name, pcells); rv = ERANGE; break; } if (cnt == idx) { *cells= malloc(pcells * sizeof(**cells), M_OFWPROP, M_WAITOK); *producer = pnode; *ncells = pcells; for (j = 0; j < pcells; j++) (*cells)[j] = elems[i + j]; rv = 0; break; } } if (elems != NULL) free(elems, M_OFWPROP); return (rv); } /* * Find index of string in string list property (case sensitive). */ int ofw_bus_find_string_index(phandle_t node, const char *list_name, const char *name, int *idx) { char *elems; int rv, i, cnt, nelems; elems = NULL; nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems); if (nelems <= 0) return (ENOENT); rv = ENOENT; for (i = 0, cnt = 0; i < nelems; cnt++) { if (strcmp(elems + i, name) == 0) { *idx = cnt; rv = 0; break; } i += strlen(elems + i) + 1; } if (elems != NULL) free(elems, M_OFWPROP); return (rv); } /* * Create zero terminated array of strings from string list property. */ int ofw_bus_string_list_to_array(phandle_t node, const char *list_name, - const char ***array) + const char ***out_array) { char *elems, *tptr; + const char **array; int i, cnt, nelems, len; elems = NULL; nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems); if (nelems <= 0) return (nelems); /* Count number of strings. */ for (i = 0, cnt = 0; i < nelems; cnt++) i += strlen(elems + i) + 1; /* Allocate space for arrays and all strings. */ - *array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP, + array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP, M_WAITOK); /* Get address of first string. */ - tptr = (char *)(*array + cnt); + tptr = (char *)(array + cnt + 1); /* Copy strings. */ memcpy(tptr, elems, nelems); free(elems, M_OFWPROP); /* Fill string pointers. */ for (i = 0, cnt = 0; i < nelems; cnt++) { - len = strlen(tptr + i) + 1; - *array[cnt] = tptr; + len = strlen(tptr) + 1; + array[cnt] = tptr; i += len; tptr += len; } - *array[cnt] = 0; + array[cnt] = 0; + *out_array = array; return (cnt); } Index: projects/release-pkg/sys/dev/pci/pcireg.h =================================================================== --- projects/release-pkg/sys/dev/pci/pcireg.h (revision 294447) +++ projects/release-pkg/sys/dev/pci/pcireg.h (revision 294448) @@ -1,969 +1,972 @@ /*- * Copyright (c) 1997, Stefan Esser * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ /* * PCIM_xxx: mask to locate subfield in register * PCIR_xxx: config register offset * PCIC_xxx: device class * PCIS_xxx: device subclass * PCIP_xxx: device programming interface * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) * PCID_xxx: device ID * PCIY_xxx: capability identification number * PCIZ_xxx: extended capability identification number */ /* some PCI bus constants */ #define PCI_DOMAINMAX 65535 /* highest supported domain number */ #define PCI_BUSMAX 255 /* highest supported bus number */ #define PCI_SLOTMAX 31 /* highest supported slot number */ #define PCI_FUNCMAX 7 /* highest supported function number */ #define PCI_REGMAX 255 /* highest supported config register addr. */ #define PCIE_REGMAX 4095 /* highest supported config register addr. */ #define PCI_MAXHDRTYPE 2 #define PCIE_ARI_SLOTMAX 0 #define PCIE_ARI_FUNCMAX 255 #define PCI_RID_DOMAIN_SHIFT 16 #define PCI_RID_BUS_SHIFT 8 #define PCI_RID_SLOT_SHIFT 3 #define PCI_RID_FUNC_SHIFT 0 #define PCI_RID(bus, slot, func) \ ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \ (((slot) & PCI_SLOTMAX) << PCI_RID_SLOT_SHIFT) | \ (((func) & PCI_FUNCMAX) << PCI_RID_FUNC_SHIFT)) #define PCI_ARI_RID(bus, func) \ ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \ (((func) & PCIE_ARI_FUNCMAX) << PCI_RID_FUNC_SHIFT)) #define PCI_RID2BUS(rid) (((rid) >> PCI_RID_BUS_SHIFT) & PCI_BUSMAX) #define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) #define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) #define PCIE_ARI_RID2SLOT(rid) (0) #define PCIE_ARI_RID2FUNC(rid) \ (((rid) >> PCI_RID_FUNC_SHIFT) & PCIE_ARI_FUNCMAX) #define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) #define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) /* PCI config header registers for all devices */ #define PCIR_DEVVENDOR 0x00 #define PCIR_VENDOR 0x00 #define PCIR_DEVICE 0x02 #define PCIR_COMMAND 0x04 #define PCIM_CMD_PORTEN 0x0001 #define PCIM_CMD_MEMEN 0x0002 #define PCIM_CMD_BUSMASTEREN 0x0004 #define PCIM_CMD_SPECIALEN 0x0008 #define PCIM_CMD_MWRICEN 0x0010 #define PCIM_CMD_PERRESPEN 0x0040 #define PCIM_CMD_SERRESPEN 0x0100 #define PCIM_CMD_BACKTOBACK 0x0200 #define PCIM_CMD_INTxDIS 0x0400 #define PCIR_STATUS 0x06 #define PCIM_STATUS_INTxSTATE 0x0008 #define PCIM_STATUS_CAPPRESENT 0x0010 #define PCIM_STATUS_66CAPABLE 0x0020 #define PCIM_STATUS_BACKTOBACK 0x0080 #define PCIM_STATUS_MDPERR 0x0100 #define PCIM_STATUS_SEL_FAST 0x0000 #define PCIM_STATUS_SEL_MEDIMUM 0x0200 #define PCIM_STATUS_SEL_SLOW 0x0400 #define PCIM_STATUS_SEL_MASK 0x0600 #define PCIM_STATUS_STABORT 0x0800 #define PCIM_STATUS_RTABORT 0x1000 #define PCIM_STATUS_RMABORT 0x2000 #define PCIM_STATUS_SERR 0x4000 #define PCIM_STATUS_PERR 0x8000 #define PCIR_REVID 0x08 #define PCIR_PROGIF 0x09 #define PCIR_SUBCLASS 0x0a #define PCIR_CLASS 0x0b #define PCIR_CACHELNSZ 0x0c #define PCIR_LATTIMER 0x0d #define PCIR_HDRTYPE 0x0e #define PCIM_HDRTYPE 0x7f #define PCIM_HDRTYPE_NORMAL 0x00 #define PCIM_HDRTYPE_BRIDGE 0x01 #define PCIM_HDRTYPE_CARDBUS 0x02 #define PCIM_MFDEV 0x80 #define PCIR_BIST 0x0f /* Capability Register Offsets */ #define PCICAP_ID 0x0 #define PCICAP_NEXTPTR 0x1 /* Capability Identification Numbers */ #define PCIY_PMG 0x01 /* PCI Power Management */ #define PCIY_AGP 0x02 /* AGP */ #define PCIY_VPD 0x03 /* Vital Product Data */ #define PCIY_SLOTID 0x04 /* Slot Identification */ #define PCIY_MSI 0x05 /* Message Signaled Interrupts */ #define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */ #define PCIY_PCIX 0x07 /* PCI-X */ #define PCIY_HT 0x08 /* HyperTransport */ #define PCIY_VENDOR 0x09 /* Vendor Unique */ #define PCIY_DEBUG 0x0a /* Debug port */ #define PCIY_CRES 0x0b /* CompactPCI central resource control */ #define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */ #define PCIY_SUBVENDOR 0x0d /* PCI-PCI bridge subvendor ID */ #define PCIY_AGP8X 0x0e /* AGP 8x */ #define PCIY_SECDEV 0x0f /* Secure Device */ #define PCIY_EXPRESS 0x10 /* PCI Express */ #define PCIY_MSIX 0x11 /* MSI-X */ #define PCIY_SATA 0x12 /* SATA */ #define PCIY_PCIAF 0x13 /* PCI Advanced Features */ /* Extended Capability Register Fields */ #define PCIR_EXTCAP 0x100 #define PCIM_EXTCAP_ID 0x0000ffff #define PCIM_EXTCAP_VER 0x000f0000 #define PCIM_EXTCAP_NEXTPTR 0xfff00000 #define PCI_EXTCAP_ID(ecap) ((ecap) & PCIM_EXTCAP_ID) #define PCI_EXTCAP_VER(ecap) (((ecap) & PCIM_EXTCAP_VER) >> 16) #define PCI_EXTCAP_NEXTPTR(ecap) (((ecap) & PCIM_EXTCAP_NEXTPTR) >> 20) /* Extended Capability Identification Numbers */ #define PCIZ_AER 0x0001 /* Advanced Error Reporting */ #define PCIZ_VC 0x0002 /* Virtual Channel if MFVC Ext Cap not set */ #define PCIZ_SERNUM 0x0003 /* Device Serial Number */ #define PCIZ_PWRBDGT 0x0004 /* Power Budgeting */ #define PCIZ_RCLINK_DCL 0x0005 /* Root Complex Link Declaration */ #define PCIZ_RCLINK_CTL 0x0006 /* Root Complex Internal Link Control */ #define PCIZ_RCEC_ASSOC 0x0007 /* Root Complex Event Collector Association */ #define PCIZ_MFVC 0x0008 /* Multi-Function Virtual Channel */ #define PCIZ_VC2 0x0009 /* Virtual Channel if MFVC Ext Cap set */ #define PCIZ_RCRB 0x000a /* RCRB Header */ #define PCIZ_VENDOR 0x000b /* Vendor Unique */ #define PCIZ_CAC 0x000c /* Configuration Access Correction -- obsolete */ #define PCIZ_ACS 0x000d /* Access Control Services */ #define PCIZ_ARI 0x000e /* Alternative Routing-ID Interpretation */ #define PCIZ_ATS 0x000f /* Address Translation Services */ #define PCIZ_SRIOV 0x0010 /* Single Root IO Virtualization */ #define PCIZ_MRIOV 0x0011 /* Multiple Root IO Virtualization */ #define PCIZ_MULTICAST 0x0012 /* Multicast */ #define PCIZ_PAGE_REQ 0x0013 /* Page Request */ #define PCIZ_AMD 0x0014 /* Reserved for AMD */ #define PCIZ_RESIZE_BAR 0x0015 /* Resizable BAR */ #define PCIZ_DPA 0x0016 /* Dynamic Power Allocation */ #define PCIZ_TPH_REQ 0x0017 /* TPH Requester */ #define PCIZ_LTR 0x0018 /* Latency Tolerance Reporting */ #define PCIZ_SEC_PCIE 0x0019 /* Secondary PCI Express */ #define PCIZ_PMUX 0x001a /* Protocol Multiplexing */ #define PCIZ_PASID 0x001b /* Process Address Space ID */ #define PCIZ_LN_REQ 0x001c /* LN Requester */ #define PCIZ_DPC 0x001d /* Downstream Porto Containment */ #define PCIZ_L1PM 0x001e /* L1 PM Substates */ /* config registers for header type 0 devices */ #define PCIR_BARS 0x10 #define PCIR_BAR(x) (PCIR_BARS + (x) * 4) #define PCIR_MAX_BAR_0 5 #define PCI_RID2BAR(rid) (((rid) - PCIR_BARS) / 4) #define PCI_BAR_IO(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) #define PCI_BAR_MEM(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE) #define PCIM_BAR_SPACE 0x00000001 #define PCIM_BAR_MEM_SPACE 0 #define PCIM_BAR_IO_SPACE 1 #define PCIM_BAR_MEM_TYPE 0x00000006 #define PCIM_BAR_MEM_32 0 #define PCIM_BAR_MEM_1MB 2 /* Locate below 1MB in PCI <= 2.1 */ #define PCIM_BAR_MEM_64 4 #define PCIM_BAR_MEM_PREFETCH 0x00000008 #define PCIM_BAR_MEM_BASE 0xfffffffffffffff0ULL #define PCIM_BAR_IO_RESERVED 0x00000002 #define PCIM_BAR_IO_BASE 0xfffffffc #define PCIR_CIS 0x28 #define PCIM_CIS_ASI_MASK 0x00000007 #define PCIM_CIS_ASI_CONFIG 0 #define PCIM_CIS_ASI_BAR0 1 #define PCIM_CIS_ASI_BAR1 2 #define PCIM_CIS_ASI_BAR2 3 #define PCIM_CIS_ASI_BAR3 4 #define PCIM_CIS_ASI_BAR4 5 #define PCIM_CIS_ASI_BAR5 6 #define PCIM_CIS_ASI_ROM 7 #define PCIM_CIS_ADDR_MASK 0x0ffffff8 #define PCIM_CIS_ROM_MASK 0xf0000000 #define PCIM_CIS_CONFIG_MASK 0xff #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e #define PCIR_BIOS 0x30 #define PCIM_BIOS_ENABLE 0x01 #define PCIM_BIOS_ADDR_MASK 0xfffff800 #define PCIR_CAP_PTR 0x34 #define PCIR_INTLINE 0x3c #define PCIR_INTPIN 0x3d #define PCIR_MINGNT 0x3e #define PCIR_MAXLAT 0x3f /* config registers for header type 1 (PCI-to-PCI bridge) devices */ #define PCIR_MAX_BAR_1 1 #define PCIR_SECSTAT_1 0x1e #define PCIR_PRIBUS_1 0x18 #define PCIR_SECBUS_1 0x19 #define PCIR_SUBBUS_1 0x1a #define PCIR_SECLAT_1 0x1b #define PCIR_IOBASEL_1 0x1c #define PCIR_IOLIMITL_1 0x1d #define PCIR_IOBASEH_1 0x30 #define PCIR_IOLIMITH_1 0x32 #define PCIM_BRIO_16 0x0 #define PCIM_BRIO_32 0x1 #define PCIM_BRIO_MASK 0xf #define PCIR_MEMBASE_1 0x20 #define PCIR_MEMLIMIT_1 0x22 #define PCIR_PMBASEL_1 0x24 #define PCIR_PMLIMITL_1 0x26 #define PCIR_PMBASEH_1 0x28 #define PCIR_PMLIMITH_1 0x2c #define PCIM_BRPM_32 0x0 #define PCIM_BRPM_64 0x1 #define PCIM_BRPM_MASK 0xf #define PCIR_BIOS_1 0x38 #define PCIR_BRIDGECTL_1 0x3e #define PCI_PPBMEMBASE(h,l) ((((uint64_t)(h) << 32) + ((l)<<16)) & ~0xfffff) #define PCI_PPBMEMLIMIT(h,l) ((((uint64_t)(h) << 32) + ((l)<<16)) | 0xfffff) #define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) #define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) /* config registers for header type 2 (CardBus) devices */ #define PCIR_MAX_BAR_2 0 #define PCIR_CAP_PTR_2 0x14 #define PCIR_SECSTAT_2 0x16 #define PCIR_PRIBUS_2 0x18 #define PCIR_SECBUS_2 0x19 #define PCIR_SUBBUS_2 0x1a #define PCIR_SECLAT_2 0x1b #define PCIR_MEMBASE0_2 0x1c #define PCIR_MEMLIMIT0_2 0x20 #define PCIR_MEMBASE1_2 0x24 #define PCIR_MEMLIMIT1_2 0x28 #define PCIR_IOBASE0_2 0x2c #define PCIR_IOLIMIT0_2 0x30 #define PCIR_IOBASE1_2 0x34 #define PCIR_IOLIMIT1_2 0x38 #define PCIM_CBBIO_16 0x0 #define PCIM_CBBIO_32 0x1 #define PCIM_CBBIO_MASK 0x3 #define PCIR_BRIDGECTL_2 0x3e #define PCIR_SUBVEND_2 0x40 #define PCIR_SUBDEV_2 0x42 #define PCIR_PCCARDIF_2 0x44 #define PCI_CBBMEMBASE(l) ((l) & ~0xfffff) #define PCI_CBBMEMLIMIT(l) ((l) | 0xfffff) #define PCI_CBBIOBASE(l) ((l) & ~0x3) #define PCI_CBBIOLIMIT(l) ((l) | 0x3) /* PCI device class, subclass and programming interface definitions */ #define PCIC_OLD 0x00 #define PCIS_OLD_NONVGA 0x00 #define PCIS_OLD_VGA 0x01 #define PCIC_STORAGE 0x01 #define PCIS_STORAGE_SCSI 0x00 #define PCIS_STORAGE_IDE 0x01 #define PCIP_STORAGE_IDE_MODEPRIM 0x01 #define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 #define PCIP_STORAGE_IDE_MODESEC 0x04 #define PCIP_STORAGE_IDE_PROGINDSEC 0x08 #define PCIP_STORAGE_IDE_MASTERDEV 0x80 #define PCIS_STORAGE_FLOPPY 0x02 #define PCIS_STORAGE_IPI 0x03 #define PCIS_STORAGE_RAID 0x04 #define PCIS_STORAGE_ATA_ADMA 0x05 #define PCIS_STORAGE_SATA 0x06 #define PCIP_STORAGE_SATA_AHCI_1_0 0x01 #define PCIS_STORAGE_SAS 0x07 #define PCIS_STORAGE_NVM 0x08 #define PCIP_STORAGE_NVM_NVMHCI_1_0 0x01 #define PCIP_STORAGE_NVM_ENTERPRISE_NVMHCI_1_0 0x02 #define PCIS_STORAGE_OTHER 0x80 #define PCIC_NETWORK 0x02 #define PCIS_NETWORK_ETHERNET 0x00 #define PCIS_NETWORK_TOKENRING 0x01 #define PCIS_NETWORK_FDDI 0x02 #define PCIS_NETWORK_ATM 0x03 #define PCIS_NETWORK_ISDN 0x04 #define PCIS_NETWORK_WORLDFIP 0x05 #define PCIS_NETWORK_PICMG 0x06 #define PCIS_NETWORK_OTHER 0x80 #define PCIC_DISPLAY 0x03 #define PCIS_DISPLAY_VGA 0x00 #define PCIS_DISPLAY_XGA 0x01 #define PCIS_DISPLAY_3D 0x02 #define PCIS_DISPLAY_OTHER 0x80 #define PCIC_MULTIMEDIA 0x04 #define PCIS_MULTIMEDIA_VIDEO 0x00 #define PCIS_MULTIMEDIA_AUDIO 0x01 #define PCIS_MULTIMEDIA_TELE 0x02 #define PCIS_MULTIMEDIA_HDA 0x03 #define PCIS_MULTIMEDIA_OTHER 0x80 #define PCIC_MEMORY 0x05 #define PCIS_MEMORY_RAM 0x00 #define PCIS_MEMORY_FLASH 0x01 #define PCIS_MEMORY_OTHER 0x80 #define PCIC_BRIDGE 0x06 #define PCIS_BRIDGE_HOST 0x00 #define PCIS_BRIDGE_ISA 0x01 #define PCIS_BRIDGE_EISA 0x02 #define PCIS_BRIDGE_MCA 0x03 #define PCIS_BRIDGE_PCI 0x04 #define PCIP_BRIDGE_PCI_SUBTRACTIVE 0x01 #define PCIS_BRIDGE_PCMCIA 0x05 #define PCIS_BRIDGE_NUBUS 0x06 #define PCIS_BRIDGE_CARDBUS 0x07 #define PCIS_BRIDGE_RACEWAY 0x08 #define PCIS_BRIDGE_PCI_TRANSPARENT 0x09 #define PCIS_BRIDGE_INFINIBAND 0x0a #define PCIS_BRIDGE_OTHER 0x80 #define PCIC_SIMPLECOMM 0x07 #define PCIS_SIMPLECOMM_UART 0x00 #define PCIP_SIMPLECOMM_UART_8250 0x00 #define PCIP_SIMPLECOMM_UART_16450A 0x01 #define PCIP_SIMPLECOMM_UART_16550A 0x02 #define PCIP_SIMPLECOMM_UART_16650A 0x03 #define PCIP_SIMPLECOMM_UART_16750A 0x04 #define PCIP_SIMPLECOMM_UART_16850A 0x05 #define PCIP_SIMPLECOMM_UART_16950A 0x06 #define PCIS_SIMPLECOMM_PAR 0x01 #define PCIS_SIMPLECOMM_MULSER 0x02 #define PCIS_SIMPLECOMM_MODEM 0x03 #define PCIS_SIMPLECOMM_GPIB 0x04 #define PCIS_SIMPLECOMM_SMART_CARD 0x05 #define PCIS_SIMPLECOMM_OTHER 0x80 #define PCIC_BASEPERIPH 0x08 #define PCIS_BASEPERIPH_PIC 0x00 #define PCIP_BASEPERIPH_PIC_8259A 0x00 #define PCIP_BASEPERIPH_PIC_ISA 0x01 #define PCIP_BASEPERIPH_PIC_EISA 0x02 #define PCIP_BASEPERIPH_PIC_IO_APIC 0x10 #define PCIP_BASEPERIPH_PIC_IOX_APIC 0x20 #define PCIS_BASEPERIPH_DMA 0x01 #define PCIS_BASEPERIPH_TIMER 0x02 #define PCIS_BASEPERIPH_RTC 0x03 #define PCIS_BASEPERIPH_PCIHOT 0x04 #define PCIS_BASEPERIPH_SDHC 0x05 #define PCIS_BASEPERIPH_IOMMU 0x06 #define PCIS_BASEPERIPH_OTHER 0x80 #define PCIC_INPUTDEV 0x09 #define PCIS_INPUTDEV_KEYBOARD 0x00 #define PCIS_INPUTDEV_DIGITIZER 0x01 #define PCIS_INPUTDEV_MOUSE 0x02 #define PCIS_INPUTDEV_SCANNER 0x03 #define PCIS_INPUTDEV_GAMEPORT 0x04 #define PCIS_INPUTDEV_OTHER 0x80 #define PCIC_DOCKING 0x0a #define PCIS_DOCKING_GENERIC 0x00 #define PCIS_DOCKING_OTHER 0x80 #define PCIC_PROCESSOR 0x0b #define PCIS_PROCESSOR_386 0x00 #define PCIS_PROCESSOR_486 0x01 #define PCIS_PROCESSOR_PENTIUM 0x02 #define PCIS_PROCESSOR_ALPHA 0x10 #define PCIS_PROCESSOR_POWERPC 0x20 #define PCIS_PROCESSOR_MIPS 0x30 #define PCIS_PROCESSOR_COPROC 0x40 #define PCIC_SERIALBUS 0x0c #define PCIS_SERIALBUS_FW 0x00 #define PCIS_SERIALBUS_ACCESS 0x01 #define PCIS_SERIALBUS_SSA 0x02 #define PCIS_SERIALBUS_USB 0x03 #define PCIP_SERIALBUS_USB_UHCI 0x00 #define PCIP_SERIALBUS_USB_OHCI 0x10 #define PCIP_SERIALBUS_USB_EHCI 0x20 #define PCIP_SERIALBUS_USB_XHCI 0x30 #define PCIP_SERIALBUS_USB_DEVICE 0xfe #define PCIS_SERIALBUS_FC 0x04 #define PCIS_SERIALBUS_SMBUS 0x05 #define PCIS_SERIALBUS_INFINIBAND 0x06 #define PCIS_SERIALBUS_IPMI 0x07 #define PCIP_SERIALBUS_IPMI_SMIC 0x00 #define PCIP_SERIALBUS_IPMI_KCS 0x01 #define PCIP_SERIALBUS_IPMI_BT 0x02 #define PCIS_SERIALBUS_SERCOS 0x08 #define PCIS_SERIALBUS_CANBUS 0x09 #define PCIC_WIRELESS 0x0d #define PCIS_WIRELESS_IRDA 0x00 #define PCIS_WIRELESS_IR 0x01 #define PCIS_WIRELESS_RF 0x10 #define PCIS_WIRELESS_BLUETOOTH 0x11 #define PCIS_WIRELESS_BROADBAND 0x12 #define PCIS_WIRELESS_80211A 0x20 #define PCIS_WIRELESS_80211B 0x21 #define PCIS_WIRELESS_OTHER 0x80 #define PCIC_INTELLIIO 0x0e #define PCIS_INTELLIIO_I2O 0x00 #define PCIC_SATCOM 0x0f #define PCIS_SATCOM_TV 0x01 #define PCIS_SATCOM_AUDIO 0x02 #define PCIS_SATCOM_VOICE 0x03 #define PCIS_SATCOM_DATA 0x04 #define PCIC_CRYPTO 0x10 #define PCIS_CRYPTO_NETCOMP 0x00 #define PCIS_CRYPTO_ENTERTAIN 0x10 #define PCIS_CRYPTO_OTHER 0x80 #define PCIC_DASP 0x11 #define PCIS_DASP_DPIO 0x00 #define PCIS_DASP_PERFCNTRS 0x01 #define PCIS_DASP_COMM_SYNC 0x10 #define PCIS_DASP_MGMT_CARD 0x20 #define PCIS_DASP_OTHER 0x80 #define PCIC_OTHER 0xff /* Bridge Control Values. */ #define PCIB_BCR_PERR_ENABLE 0x0001 #define PCIB_BCR_SERR_ENABLE 0x0002 #define PCIB_BCR_ISA_ENABLE 0x0004 #define PCIB_BCR_VGA_ENABLE 0x0008 #define PCIB_BCR_MASTER_ABORT_MODE 0x0020 #define PCIB_BCR_SECBUS_RESET 0x0040 #define PCIB_BCR_SECBUS_BACKTOBACK 0x0080 #define PCIB_BCR_PRI_DISCARD_TIMEOUT 0x0100 #define PCIB_BCR_SEC_DISCARD_TIMEOUT 0x0200 #define PCIB_BCR_DISCARD_TIMER_STATUS 0x0400 #define PCIB_BCR_DISCARD_TIMER_SERREN 0x0800 #define CBB_BCR_PERR_ENABLE 0x0001 #define CBB_BCR_SERR_ENABLE 0x0002 #define CBB_BCR_ISA_ENABLE 0x0004 #define CBB_BCR_VGA_ENABLE 0x0008 #define CBB_BCR_MASTER_ABORT_MODE 0x0020 #define CBB_BCR_CARDBUS_RESET 0x0040 #define CBB_BCR_IREQ_INT_ENABLE 0x0080 #define CBB_BCR_PREFETCH_0_ENABLE 0x0100 #define CBB_BCR_PREFETCH_1_ENABLE 0x0200 #define CBB_BCR_WRITE_POSTING_ENABLE 0x0400 /* PCI power manangement */ #define PCIR_POWER_CAP 0x2 #define PCIM_PCAP_SPEC 0x0007 #define PCIM_PCAP_PMEREQCLK 0x0008 #define PCIM_PCAP_DEVSPECINIT 0x0020 #define PCIM_PCAP_AUXPWR_0 0x0000 #define PCIM_PCAP_AUXPWR_55 0x0040 #define PCIM_PCAP_AUXPWR_100 0x0080 #define PCIM_PCAP_AUXPWR_160 0x00c0 #define PCIM_PCAP_AUXPWR_220 0x0100 #define PCIM_PCAP_AUXPWR_270 0x0140 #define PCIM_PCAP_AUXPWR_320 0x0180 #define PCIM_PCAP_AUXPWR_375 0x01c0 #define PCIM_PCAP_AUXPWRMASK 0x01c0 #define PCIM_PCAP_D1SUPP 0x0200 #define PCIM_PCAP_D2SUPP 0x0400 #define PCIM_PCAP_D0PME 0x0800 #define PCIM_PCAP_D1PME 0x1000 #define PCIM_PCAP_D2PME 0x2000 #define PCIM_PCAP_D3PME_HOT 0x4000 #define PCIM_PCAP_D3PME_COLD 0x8000 #define PCIR_POWER_STATUS 0x4 #define PCIM_PSTAT_D0 0x0000 #define PCIM_PSTAT_D1 0x0001 #define PCIM_PSTAT_D2 0x0002 #define PCIM_PSTAT_D3 0x0003 #define PCIM_PSTAT_DMASK 0x0003 #define PCIM_PSTAT_NOSOFTRESET 0x0008 #define PCIM_PSTAT_PMEENABLE 0x0100 #define PCIM_PSTAT_D0POWER 0x0000 #define PCIM_PSTAT_D1POWER 0x0200 #define PCIM_PSTAT_D2POWER 0x0400 #define PCIM_PSTAT_D3POWER 0x0600 #define PCIM_PSTAT_D0HEAT 0x0800 #define PCIM_PSTAT_D1HEAT 0x0a00 #define PCIM_PSTAT_D2HEAT 0x0c00 #define PCIM_PSTAT_D3HEAT 0x0e00 #define PCIM_PSTAT_DATASELMASK 0x1e00 #define PCIM_PSTAT_DATAUNKN 0x0000 #define PCIM_PSTAT_DATADIV10 0x2000 #define PCIM_PSTAT_DATADIV100 0x4000 #define PCIM_PSTAT_DATADIV1000 0x6000 #define PCIM_PSTAT_DATADIVMASK 0x6000 #define PCIM_PSTAT_PME 0x8000 #define PCIR_POWER_BSE 0x6 #define PCIM_PMCSR_BSE_D3B3 0x00 #define PCIM_PMCSR_BSE_D3B2 0x40 #define PCIM_PMCSR_BSE_BPCCE 0x80 #define PCIR_POWER_DATA 0x7 /* VPD capability registers */ #define PCIR_VPD_ADDR 0x2 #define PCIR_VPD_DATA 0x4 /* PCI Message Signalled Interrupts (MSI) */ #define PCIR_MSI_CTRL 0x2 #define PCIM_MSICTRL_VECTOR 0x0100 #define PCIM_MSICTRL_64BIT 0x0080 #define PCIM_MSICTRL_MME_MASK 0x0070 #define PCIM_MSICTRL_MME_1 0x0000 #define PCIM_MSICTRL_MME_2 0x0010 #define PCIM_MSICTRL_MME_4 0x0020 #define PCIM_MSICTRL_MME_8 0x0030 #define PCIM_MSICTRL_MME_16 0x0040 #define PCIM_MSICTRL_MME_32 0x0050 #define PCIM_MSICTRL_MMC_MASK 0x000E #define PCIM_MSICTRL_MMC_1 0x0000 #define PCIM_MSICTRL_MMC_2 0x0002 #define PCIM_MSICTRL_MMC_4 0x0004 #define PCIM_MSICTRL_MMC_8 0x0006 #define PCIM_MSICTRL_MMC_16 0x0008 #define PCIM_MSICTRL_MMC_32 0x000A #define PCIM_MSICTRL_MSI_ENABLE 0x0001 #define PCIR_MSI_ADDR 0x4 #define PCIR_MSI_ADDR_HIGH 0x8 #define PCIR_MSI_DATA 0x8 #define PCIR_MSI_DATA_64BIT 0xc #define PCIR_MSI_MASK 0x10 #define PCIR_MSI_PENDING 0x14 /* PCI-X definitions */ /* For header type 0 devices */ #define PCIXR_COMMAND 0x2 #define PCIXM_COMMAND_DPERR_E 0x0001 /* Data Parity Error Recovery */ #define PCIXM_COMMAND_ERO 0x0002 /* Enable Relaxed Ordering */ #define PCIXM_COMMAND_MAX_READ 0x000c /* Maximum Burst Read Count */ #define PCIXM_COMMAND_MAX_READ_512 0x0000 #define PCIXM_COMMAND_MAX_READ_1024 0x0004 #define PCIXM_COMMAND_MAX_READ_2048 0x0008 #define PCIXM_COMMAND_MAX_READ_4096 0x000c #define PCIXM_COMMAND_MAX_SPLITS 0x0070 /* Maximum Split Transactions */ #define PCIXM_COMMAND_MAX_SPLITS_1 0x0000 #define PCIXM_COMMAND_MAX_SPLITS_2 0x0010 #define PCIXM_COMMAND_MAX_SPLITS_3 0x0020 #define PCIXM_COMMAND_MAX_SPLITS_4 0x0030 #define PCIXM_COMMAND_MAX_SPLITS_8 0x0040 #define PCIXM_COMMAND_MAX_SPLITS_12 0x0050 #define PCIXM_COMMAND_MAX_SPLITS_16 0x0060 #define PCIXM_COMMAND_MAX_SPLITS_32 0x0070 #define PCIXM_COMMAND_VERSION 0x3000 #define PCIXR_STATUS 0x4 #define PCIXM_STATUS_DEVFN 0x000000FF #define PCIXM_STATUS_BUS 0x0000FF00 #define PCIXM_STATUS_64BIT 0x00010000 #define PCIXM_STATUS_133CAP 0x00020000 #define PCIXM_STATUS_SC_DISCARDED 0x00040000 #define PCIXM_STATUS_UNEXP_SC 0x00080000 #define PCIXM_STATUS_COMPLEX_DEV 0x00100000 #define PCIXM_STATUS_MAX_READ 0x00600000 #define PCIXM_STATUS_MAX_READ_512 0x00000000 #define PCIXM_STATUS_MAX_READ_1024 0x00200000 #define PCIXM_STATUS_MAX_READ_2048 0x00400000 #define PCIXM_STATUS_MAX_READ_4096 0x00600000 #define PCIXM_STATUS_MAX_SPLITS 0x03800000 #define PCIXM_STATUS_MAX_SPLITS_1 0x00000000 #define PCIXM_STATUS_MAX_SPLITS_2 0x00800000 #define PCIXM_STATUS_MAX_SPLITS_3 0x01000000 #define PCIXM_STATUS_MAX_SPLITS_4 0x01800000 #define PCIXM_STATUS_MAX_SPLITS_8 0x02000000 #define PCIXM_STATUS_MAX_SPLITS_12 0x02800000 #define PCIXM_STATUS_MAX_SPLITS_16 0x03000000 #define PCIXM_STATUS_MAX_SPLITS_32 0x03800000 #define PCIXM_STATUS_MAX_CUM_READ 0x1C000000 #define PCIXM_STATUS_RCVD_SC_ERR 0x20000000 #define PCIXM_STATUS_266CAP 0x40000000 #define PCIXM_STATUS_533CAP 0x80000000 /* For header type 1 devices (PCI-X bridges) */ #define PCIXR_SEC_STATUS 0x2 #define PCIXM_SEC_STATUS_64BIT 0x0001 #define PCIXM_SEC_STATUS_133CAP 0x0002 #define PCIXM_SEC_STATUS_SC_DISC 0x0004 #define PCIXM_SEC_STATUS_UNEXP_SC 0x0008 #define PCIXM_SEC_STATUS_SC_OVERRUN 0x0010 #define PCIXM_SEC_STATUS_SR_DELAYED 0x0020 #define PCIXM_SEC_STATUS_BUS_MODE 0x03c0 #define PCIXM_SEC_STATUS_VERSION 0x3000 #define PCIXM_SEC_STATUS_266CAP 0x4000 #define PCIXM_SEC_STATUS_533CAP 0x8000 #define PCIXR_BRIDGE_STATUS 0x4 #define PCIXM_BRIDGE_STATUS_DEVFN 0x000000FF #define PCIXM_BRIDGE_STATUS_BUS 0x0000FF00 #define PCIXM_BRIDGE_STATUS_64BIT 0x00010000 #define PCIXM_BRIDGE_STATUS_133CAP 0x00020000 #define PCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000 #define PCIXM_BRIDGE_STATUS_UNEXP_SC 0x00080000 #define PCIXM_BRIDGE_STATUS_SC_OVERRUN 0x00100000 #define PCIXM_BRIDGE_STATUS_SR_DELAYED 0x00200000 #define PCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000 #define PCIXM_BRIDGE_STATUS_266CAP 0x40000000 #define PCIXM_BRIDGE_STATUS_533CAP 0x80000000 /* HT (HyperTransport) Capability definitions */ #define PCIR_HT_COMMAND 0x2 #define PCIM_HTCMD_CAP_MASK 0xf800 /* Capability type. */ #define PCIM_HTCAP_SLAVE 0x0000 /* 000xx */ #define PCIM_HTCAP_HOST 0x2000 /* 001xx */ #define PCIM_HTCAP_SWITCH 0x4000 /* 01000 */ #define PCIM_HTCAP_INTERRUPT 0x8000 /* 10000 */ #define PCIM_HTCAP_REVISION_ID 0x8800 /* 10001 */ #define PCIM_HTCAP_UNITID_CLUMPING 0x9000 /* 10010 */ #define PCIM_HTCAP_EXT_CONFIG_SPACE 0x9800 /* 10011 */ #define PCIM_HTCAP_ADDRESS_MAPPING 0xa000 /* 10100 */ #define PCIM_HTCAP_MSI_MAPPING 0xa800 /* 10101 */ #define PCIM_HTCAP_DIRECT_ROUTE 0xb000 /* 10110 */ #define PCIM_HTCAP_VCSET 0xb800 /* 10111 */ #define PCIM_HTCAP_RETRY_MODE 0xc000 /* 11000 */ #define PCIM_HTCAP_X86_ENCODING 0xc800 /* 11001 */ #define PCIM_HTCAP_GEN3 0xd000 /* 11010 */ #define PCIM_HTCAP_FLE 0xd800 /* 11011 */ #define PCIM_HTCAP_PM 0xe000 /* 11100 */ #define PCIM_HTCAP_HIGH_NODE_COUNT 0xe800 /* 11101 */ /* HT MSI Mapping Capability definitions. */ #define PCIM_HTCMD_MSI_ENABLE 0x0001 #define PCIM_HTCMD_MSI_FIXED 0x0002 #define PCIR_HTMSI_ADDRESS_LO 0x4 #define PCIR_HTMSI_ADDRESS_HI 0x8 /* PCI Vendor capability definitions */ #define PCIR_VENDOR_LENGTH 0x2 #define PCIR_VENDOR_DATA 0x3 +/* PCI Device capability definitions */ +#define PCIR_DEVICE_LENGTH 0x2 + /* PCI EHCI Debug Port definitions */ #define PCIR_DEBUG_PORT 0x2 #define PCIM_DEBUG_PORT_OFFSET 0x1FFF #define PCIM_DEBUG_PORT_BAR 0xe000 /* PCI-PCI Bridge Subvendor definitions */ #define PCIR_SUBVENDCAP_ID 0x4 /* PCI Express definitions */ #define PCIER_FLAGS 0x2 #define PCIEM_FLAGS_VERSION 0x000F #define PCIEM_FLAGS_TYPE 0x00F0 #define PCIEM_TYPE_ENDPOINT 0x0000 #define PCIEM_TYPE_LEGACY_ENDPOINT 0x0010 #define PCIEM_TYPE_ROOT_PORT 0x0040 #define PCIEM_TYPE_UPSTREAM_PORT 0x0050 #define PCIEM_TYPE_DOWNSTREAM_PORT 0x0060 #define PCIEM_TYPE_PCI_BRIDGE 0x0070 #define PCIEM_TYPE_PCIE_BRIDGE 0x0080 #define PCIEM_TYPE_ROOT_INT_EP 0x0090 #define PCIEM_TYPE_ROOT_EC 0x00a0 #define PCIEM_FLAGS_SLOT 0x0100 #define PCIEM_FLAGS_IRQ 0x3e00 #define PCIER_DEVICE_CAP 0x4 #define PCIEM_CAP_MAX_PAYLOAD 0x00000007 #define PCIEM_CAP_PHANTHOM_FUNCS 0x00000018 #define PCIEM_CAP_EXT_TAG_FIELD 0x00000020 #define PCIEM_CAP_L0S_LATENCY 0x000001c0 #define PCIEM_CAP_L1_LATENCY 0x00000e00 #define PCIEM_CAP_ROLE_ERR_RPT 0x00008000 #define PCIEM_CAP_SLOT_PWR_LIM_VAL 0x03fc0000 #define PCIEM_CAP_SLOT_PWR_LIM_SCALE 0x0c000000 #define PCIEM_CAP_FLR 0x10000000 #define PCIER_DEVICE_CTL 0x8 #define PCIEM_CTL_COR_ENABLE 0x0001 #define PCIEM_CTL_NFER_ENABLE 0x0002 #define PCIEM_CTL_FER_ENABLE 0x0004 #define PCIEM_CTL_URR_ENABLE 0x0008 #define PCIEM_CTL_RELAXED_ORD_ENABLE 0x0010 #define PCIEM_CTL_MAX_PAYLOAD 0x00e0 #define PCIEM_CTL_EXT_TAG_FIELD 0x0100 #define PCIEM_CTL_PHANTHOM_FUNCS 0x0200 #define PCIEM_CTL_AUX_POWER_PM 0x0400 #define PCIEM_CTL_NOSNOOP_ENABLE 0x0800 #define PCIEM_CTL_MAX_READ_REQUEST 0x7000 #define PCIEM_CTL_BRDG_CFG_RETRY 0x8000 /* PCI-E - PCI/PCI-X bridges */ #define PCIEM_CTL_INITIATE_FLR 0x8000 /* FLR capable endpoints */ #define PCIER_DEVICE_STA 0xa #define PCIEM_STA_CORRECTABLE_ERROR 0x0001 #define PCIEM_STA_NON_FATAL_ERROR 0x0002 #define PCIEM_STA_FATAL_ERROR 0x0004 #define PCIEM_STA_UNSUPPORTED_REQ 0x0008 #define PCIEM_STA_AUX_POWER 0x0010 #define PCIEM_STA_TRANSACTION_PND 0x0020 #define PCIER_LINK_CAP 0xc #define PCIEM_LINK_CAP_MAX_SPEED 0x0000000f #define PCIEM_LINK_CAP_MAX_WIDTH 0x000003f0 #define PCIEM_LINK_CAP_ASPM 0x00000c00 #define PCIEM_LINK_CAP_L0S_EXIT 0x00007000 #define PCIEM_LINK_CAP_L1_EXIT 0x00038000 #define PCIEM_LINK_CAP_CLOCK_PM 0x00040000 #define PCIEM_LINK_CAP_SURPRISE_DOWN 0x00080000 #define PCIEM_LINK_CAP_DL_ACTIVE 0x00100000 #define PCIEM_LINK_CAP_LINK_BW_NOTIFY 0x00200000 #define PCIEM_LINK_CAP_ASPM_COMPLIANCE 0x00400000 #define PCIEM_LINK_CAP_PORT 0xff000000 #define PCIER_LINK_CTL 0x10 #define PCIEM_LINK_CTL_ASPMC_DIS 0x0000 #define PCIEM_LINK_CTL_ASPMC_L0S 0x0001 #define PCIEM_LINK_CTL_ASPMC_L1 0x0002 #define PCIEM_LINK_CTL_ASPMC 0x0003 #define PCIEM_LINK_CTL_RCB 0x0008 #define PCIEM_LINK_CTL_LINK_DIS 0x0010 #define PCIEM_LINK_CTL_RETRAIN_LINK 0x0020 #define PCIEM_LINK_CTL_COMMON_CLOCK 0x0040 #define PCIEM_LINK_CTL_EXTENDED_SYNC 0x0080 #define PCIEM_LINK_CTL_ECPM 0x0100 #define PCIEM_LINK_CTL_HAWD 0x0200 #define PCIEM_LINK_CTL_LBMIE 0x0400 #define PCIEM_LINK_CTL_LABIE 0x0800 #define PCIER_LINK_STA 0x12 #define PCIEM_LINK_STA_SPEED 0x000f #define PCIEM_LINK_STA_WIDTH 0x03f0 #define PCIEM_LINK_STA_TRAINING_ERROR 0x0400 #define PCIEM_LINK_STA_TRAINING 0x0800 #define PCIEM_LINK_STA_SLOT_CLOCK 0x1000 #define PCIEM_LINK_STA_DL_ACTIVE 0x2000 #define PCIEM_LINK_STA_LINK_BW_MGMT 0x4000 #define PCIEM_LINK_STA_LINK_AUTO_BW 0x8000 #define PCIER_SLOT_CAP 0x14 #define PCIEM_SLOT_CAP_APB 0x00000001 #define PCIEM_SLOT_CAP_PCP 0x00000002 #define PCIEM_SLOT_CAP_MRLSP 0x00000004 #define PCIEM_SLOT_CAP_AIP 0x00000008 #define PCIEM_SLOT_CAP_PIP 0x00000010 #define PCIEM_SLOT_CAP_HPS 0x00000020 #define PCIEM_SLOT_CAP_HPC 0x00000040 #define PCIEM_SLOT_CAP_SPLV 0x00007f80 #define PCIEM_SLOT_CAP_SPLS 0x00018000 #define PCIEM_SLOT_CAP_EIP 0x00020000 #define PCIEM_SLOT_CAP_NCCS 0x00040000 #define PCIEM_SLOT_CAP_PSN 0xfff80000 #define PCIER_SLOT_CTL 0x18 #define PCIEM_SLOT_CTL_ABPE 0x0001 #define PCIEM_SLOT_CTL_PFDE 0x0002 #define PCIEM_SLOT_CTL_MRLSCE 0x0004 #define PCIEM_SLOT_CTL_PDCE 0x0008 #define PCIEM_SLOT_CTL_CCIE 0x0010 #define PCIEM_SLOT_CTL_HPIE 0x0020 #define PCIEM_SLOT_CTL_AIC 0x00c0 #define PCIEM_SLOT_CTL_PIC 0x0300 #define PCIEM_SLOT_CTL_PCC 0x0400 #define PCIEM_SLOT_CTL_EIC 0x0800 #define PCIEM_SLOT_CTL_DLLSCE 0x1000 #define PCIER_SLOT_STA 0x1a #define PCIEM_SLOT_STA_ABP 0x0001 #define PCIEM_SLOT_STA_PFD 0x0002 #define PCIEM_SLOT_STA_MRLSC 0x0004 #define PCIEM_SLOT_STA_PDC 0x0008 #define PCIEM_SLOT_STA_CC 0x0010 #define PCIEM_SLOT_STA_MRLSS 0x0020 #define PCIEM_SLOT_STA_PDS 0x0040 #define PCIEM_SLOT_STA_EIS 0x0080 #define PCIEM_SLOT_STA_DLLSC 0x0100 #define PCIER_ROOT_CTL 0x1c #define PCIEM_ROOT_CTL_SERR_CORR 0x0001 #define PCIEM_ROOT_CTL_SERR_NONFATAL 0x0002 #define PCIEM_ROOT_CTL_SERR_FATAL 0x0004 #define PCIEM_ROOT_CTL_PME 0x0008 #define PCIEM_ROOT_CTL_CRS_VIS 0x0010 #define PCIER_ROOT_CAP 0x1e #define PCIEM_ROOT_CAP_CRS_VIS 0x0001 #define PCIER_ROOT_STA 0x20 #define PCIEM_ROOT_STA_PME_REQID_MASK 0x0000ffff #define PCIEM_ROOT_STA_PME_STATUS 0x00010000 #define PCIEM_ROOT_STA_PME_PEND 0x00020000 #define PCIER_DEVICE_CAP2 0x24 #define PCIEM_CAP2_ARI 0x20 #define PCIER_DEVICE_CTL2 0x28 #define PCIEM_CTL2_COMP_TIMEOUT_VAL 0x000f #define PCIEM_CTL2_COMP_TIMEOUT_DIS 0x0010 #define PCIEM_CTL2_ARI 0x0020 #define PCIEM_CTL2_ATOMIC_REQ_ENABLE 0x0040 #define PCIEM_CTL2_ATOMIC_EGR_BLOCK 0x0080 #define PCIEM_CTL2_ID_ORDERED_REQ_EN 0x0100 #define PCIEM_CTL2_ID_ORDERED_CMP_EN 0x0200 #define PCIEM_CTL2_LTR_ENABLE 0x0400 #define PCIEM_CTL2_OBFF 0x6000 #define PCIEM_OBFF_DISABLE 0x0000 #define PCIEM_OBFF_MSGA_ENABLE 0x2000 #define PCIEM_OBFF_MSGB_ENABLE 0x4000 #define PCIEM_OBFF_WAKE_ENABLE 0x6000 #define PCIEM_CTL2_END2END_TLP 0x8000 #define PCIER_DEVICE_STA2 0x2a #define PCIER_LINK_CAP2 0x2c #define PCIER_LINK_CTL2 0x30 #define PCIER_LINK_STA2 0x32 #define PCIER_SLOT_CAP2 0x34 #define PCIER_SLOT_CTL2 0x38 #define PCIER_SLOT_STA2 0x3a /* MSI-X definitions */ #define PCIR_MSIX_CTRL 0x2 #define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 #define PCIM_MSIXCTRL_FUNCTION_MASK 0x4000 #define PCIM_MSIXCTRL_TABLE_SIZE 0x07FF #define PCIR_MSIX_TABLE 0x4 #define PCIR_MSIX_PBA 0x8 #define PCIM_MSIX_BIR_MASK 0x7 #define PCIM_MSIX_BIR_BAR_10 0 #define PCIM_MSIX_BIR_BAR_14 1 #define PCIM_MSIX_BIR_BAR_18 2 #define PCIM_MSIX_BIR_BAR_1C 3 #define PCIM_MSIX_BIR_BAR_20 4 #define PCIM_MSIX_BIR_BAR_24 5 #define PCIM_MSIX_VCTRL_MASK 0x1 /* PCI Advanced Features definitions */ #define PCIR_PCIAF_CAP 0x3 #define PCIM_PCIAFCAP_TP 0x01 #define PCIM_PCIAFCAP_FLR 0x02 #define PCIR_PCIAF_CTRL 0x4 #define PCIR_PCIAFCTRL_FLR 0x01 #define PCIR_PCIAF_STATUS 0x5 #define PCIR_PCIAFSTATUS_TP 0x01 /* Advanced Error Reporting */ #define PCIR_AER_UC_STATUS 0x04 #define PCIM_AER_UC_TRAINING_ERROR 0x00000001 #define PCIM_AER_UC_DL_PROTOCOL_ERROR 0x00000010 #define PCIM_AER_UC_SURPRISE_LINK_DOWN 0x00000020 #define PCIM_AER_UC_POISONED_TLP 0x00001000 #define PCIM_AER_UC_FC_PROTOCOL_ERROR 0x00002000 #define PCIM_AER_UC_COMPLETION_TIMEOUT 0x00004000 #define PCIM_AER_UC_COMPLETER_ABORT 0x00008000 #define PCIM_AER_UC_UNEXPECTED_COMPLETION 0x00010000 #define PCIM_AER_UC_RECEIVER_OVERFLOW 0x00020000 #define PCIM_AER_UC_MALFORMED_TLP 0x00040000 #define PCIM_AER_UC_ECRC_ERROR 0x00080000 #define PCIM_AER_UC_UNSUPPORTED_REQUEST 0x00100000 #define PCIM_AER_UC_ACS_VIOLATION 0x00200000 #define PCIM_AER_UC_INTERNAL_ERROR 0x00400000 #define PCIM_AER_UC_MC_BLOCKED_TLP 0x00800000 #define PCIM_AER_UC_ATOMIC_EGRESS_BLK 0x01000000 #define PCIM_AER_UC_TLP_PREFIX_BLOCKED 0x02000000 #define PCIR_AER_UC_MASK 0x08 /* Shares bits with UC_STATUS */ #define PCIR_AER_UC_SEVERITY 0x0c /* Shares bits with UC_STATUS */ #define PCIR_AER_COR_STATUS 0x10 #define PCIM_AER_COR_RECEIVER_ERROR 0x00000001 #define PCIM_AER_COR_BAD_TLP 0x00000040 #define PCIM_AER_COR_BAD_DLLP 0x00000080 #define PCIM_AER_COR_REPLAY_ROLLOVER 0x00000100 #define PCIM_AER_COR_REPLAY_TIMEOUT 0x00001000 #define PCIM_AER_COR_ADVISORY_NF_ERROR 0x00002000 #define PCIM_AER_COR_INTERNAL_ERROR 0x00004000 #define PCIM_AER_COR_HEADER_LOG_OVFLOW 0x00008000 #define PCIR_AER_COR_MASK 0x14 /* Shares bits with COR_STATUS */ #define PCIR_AER_CAP_CONTROL 0x18 #define PCIM_AER_FIRST_ERROR_PTR 0x0000001f #define PCIM_AER_ECRC_GEN_CAPABLE 0x00000020 #define PCIM_AER_ECRC_GEN_ENABLE 0x00000040 #define PCIM_AER_ECRC_CHECK_CAPABLE 0x00000080 #define PCIM_AER_ECRC_CHECK_ENABLE 0x00000100 #define PCIM_AER_MULT_HDR_CAPABLE 0x00000200 #define PCIM_AER_MULT_HDR_ENABLE 0x00000400 #define PCIM_AER_TLP_PREFIX_LOG_PRESENT 0x00000800 #define PCIR_AER_HEADER_LOG 0x1c #define PCIR_AER_ROOTERR_CMD 0x2c /* Only for root complex ports */ #define PCIM_AER_ROOTERR_COR_ENABLE 0x00000001 #define PCIM_AER_ROOTERR_NF_ENABLE 0x00000002 #define PCIM_AER_ROOTERR_F_ENABLE 0x00000004 #define PCIR_AER_ROOTERR_STATUS 0x30 /* Only for root complex ports */ #define PCIM_AER_ROOTERR_COR_ERR 0x00000001 #define PCIM_AER_ROOTERR_MULTI_COR_ERR 0x00000002 #define PCIM_AER_ROOTERR_UC_ERR 0x00000004 #define PCIM_AER_ROOTERR_MULTI_UC_ERR 0x00000008 #define PCIM_AER_ROOTERR_FIRST_UC_FATAL 0x00000010 #define PCIM_AER_ROOTERR_NF_ERR 0x00000020 #define PCIM_AER_ROOTERR_F_ERR 0x00000040 #define PCIM_AER_ROOTERR_INT_MESSAGE 0xf8000000 #define PCIR_AER_COR_SOURCE_ID 0x34 /* Only for root complex ports */ #define PCIR_AER_ERR_SOURCE_ID 0x36 /* Only for root complex ports */ #define PCIR_AER_TLP_PREFIX_LOG 0x38 /* Only for TLP prefix functions */ /* Virtual Channel definitions */ #define PCIR_VC_CAP1 0x04 #define PCIM_VC_CAP1_EXT_COUNT 0x00000007 #define PCIM_VC_CAP1_LOWPRI_EXT_COUNT 0x00000070 #define PCIR_VC_CAP2 0x08 #define PCIR_VC_CONTROL 0x0C #define PCIR_VC_STATUS 0x0E #define PCIR_VC_RESOURCE_CAP(n) (0x10 + (n) * 0x0C) #define PCIR_VC_RESOURCE_CTL(n) (0x14 + (n) * 0x0C) #define PCIR_VC_RESOURCE_STA(n) (0x18 + (n) * 0x0C) /* Serial Number definitions */ #define PCIR_SERIAL_LOW 0x04 #define PCIR_SERIAL_HIGH 0x08 /* SR-IOV definitions */ #define PCIR_SRIOV_CTL 0x08 #define PCIM_SRIOV_VF_EN 0x01 #define PCIM_SRIOV_VF_MSE 0x08 /* Memory space enable. */ #define PCIM_SRIOV_ARI_EN 0x10 #define PCIR_SRIOV_TOTAL_VFS 0x0E #define PCIR_SRIOV_NUM_VFS 0x10 #define PCIR_SRIOV_VF_OFF 0x14 #define PCIR_SRIOV_VF_STRIDE 0x16 #define PCIR_SRIOV_VF_DID 0x1A #define PCIR_SRIOV_PAGE_CAP 0x1C #define PCIR_SRIOV_PAGE_SIZE 0x20 #define PCI_SRIOV_BASE_PAGE_SHIFT 12 #define PCIR_SRIOV_BARS 0x24 #define PCIR_SRIOV_BAR(x) (PCIR_SRIOV_BARS + (x) * 4) Index: projects/release-pkg/sys/dev/uart/uart_dev_ns8250.c =================================================================== --- projects/release-pkg/sys/dev/uart/uart_dev_ns8250.c (revision 294447) +++ projects/release-pkg/sys/dev/uart/uart_dev_ns8250.c (revision 294448) @@ -1,1026 +1,1030 @@ /*- * Copyright (c) 2003 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opt_platform.h" #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include #include #ifdef FDT #include #endif #include #include #include #include #include "uart_if.h" #define DEFAULT_RCLK 1843200 /* * Set the default baudrate tolerance to 3.0%. * * Some embedded boards have odd reference clocks (eg 25MHz) * and we need to handle higher variances in the target baud rate. */ #ifndef UART_DEV_TOLERANCE_PCT #define UART_DEV_TOLERANCE_PCT 30 #endif /* UART_DEV_TOLERANCE_PCT */ static int broken_txfifo = 0; SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RWTUN, &broken_txfifo, 0, "UART FIFO has QEMU emulation bug"); /* * Clear pending interrupts. THRE is cleared by reading IIR. Data * that may have been received gets lost here. */ static void ns8250_clrint(struct uart_bas *bas) { uint8_t iir, lsr; iir = uart_getreg(bas, REG_IIR); while ((iir & IIR_NOPEND) == 0) { iir &= IIR_IMASK; if (iir == IIR_RLS) { lsr = uart_getreg(bas, REG_LSR); if (lsr & (LSR_BI|LSR_FE|LSR_PE)) (void)uart_getreg(bas, REG_DATA); } else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) (void)uart_getreg(bas, REG_DATA); else if (iir == IIR_MLSC) (void)uart_getreg(bas, REG_MSR); uart_barrier(bas); iir = uart_getreg(bas, REG_IIR); } } static int ns8250_delay(struct uart_bas *bas) { int divisor; u_char lcr; lcr = uart_getreg(bas, REG_LCR); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); /* 1/10th the time to transmit 1 character (estimate). */ if (divisor <= 134) return (16000000 * divisor / bas->rclk); return (16000 * divisor / (bas->rclk / 1000)); } static int ns8250_divisor(int rclk, int baudrate) { int actual_baud, divisor; int error; if (baudrate == 0) return (0); divisor = (rclk / (baudrate << 3) + 1) >> 1; if (divisor == 0 || divisor >= 65536) return (0); actual_baud = rclk / (divisor << 4); /* 10 times error in percent: */ error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1; /* enforce maximum error tolerance: */ if (error < -UART_DEV_TOLERANCE_PCT || error > UART_DEV_TOLERANCE_PCT) return (0); return (divisor); } static int ns8250_drain(struct uart_bas *bas, int what) { int delay, limit; delay = ns8250_delay(bas); if (what & UART_DRAIN_TRANSMITTER) { /* * Pick an arbitrary high limit to avoid getting stuck in * an infinite loop when the hardware is broken. Make the * limit high enough to handle large FIFOs. */ limit = 10*1024; while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) DELAY(delay); if (limit == 0) { /* printf("ns8250: transmitter appears stuck... "); */ return (EIO); } } if (what & UART_DRAIN_RECEIVER) { /* * Pick an arbitrary high limit to avoid getting stuck in * an infinite loop when the hardware is broken. Make the * limit high enough to handle large FIFOs and integrated * UARTs. The HP rx2600 for example has 3 UARTs on the * management board that tend to get a lot of data send * to it when the UART is first activated. */ limit=10*4096; while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) { (void)uart_getreg(bas, REG_DATA); uart_barrier(bas); DELAY(delay << 2); } if (limit == 0) { /* printf("ns8250: receiver appears broken... "); */ return (EIO); } } return (0); } /* * We can only flush UARTs with FIFOs. UARTs without FIFOs should be * drained. WARNING: this function clobbers the FIFO setting! */ static void ns8250_flush(struct uart_bas *bas, int what) { uint8_t fcr; fcr = FCR_ENABLE; if (what & UART_FLUSH_TRANSMITTER) fcr |= FCR_XMT_RST; if (what & UART_FLUSH_RECEIVER) fcr |= FCR_RCV_RST; uart_setreg(bas, REG_FCR, fcr); uart_barrier(bas); } static int ns8250_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { int divisor; uint8_t lcr; lcr = 0; if (databits >= 8) lcr |= LCR_8BITS; else if (databits == 7) lcr |= LCR_7BITS; else if (databits == 6) lcr |= LCR_6BITS; else lcr |= LCR_5BITS; if (stopbits > 1) lcr |= LCR_STOPB; lcr |= parity << 3; /* Set baudrate. */ if (baudrate > 0) { divisor = ns8250_divisor(bas->rclk, baudrate); if (divisor == 0) return (EINVAL); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); uart_setreg(bas, REG_DLL, divisor & 0xff); uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); uart_barrier(bas); } /* Set LCR and clear DLAB. */ uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); return (0); } /* * Low-level UART interface. */ static int ns8250_probe(struct uart_bas *bas); static void ns8250_init(struct uart_bas *bas, int, int, int, int); static void ns8250_term(struct uart_bas *bas); static void ns8250_putc(struct uart_bas *bas, int); static int ns8250_rxready(struct uart_bas *bas); static int ns8250_getc(struct uart_bas *bas, struct mtx *); struct uart_ops uart_ns8250_ops = { .probe = ns8250_probe, .init = ns8250_init, .term = ns8250_term, .putc = ns8250_putc, .rxready = ns8250_rxready, .getc = ns8250_getc, }; static int ns8250_probe(struct uart_bas *bas) { u_char val; /* Check known 0 bits that don't depend on DLAB. */ val = uart_getreg(bas, REG_IIR); if (val & 0x30) return (ENXIO); /* * Bit 6 of the MCR (= 0x40) appears to be 1 for the Sun1699 * chip, but otherwise doesn't seem to have a function. In * other words, uart(4) works regardless. Ignore that bit so * the probe succeeds. */ val = uart_getreg(bas, REG_MCR); if (val & 0xa0) return (ENXIO); return (0); } static void ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { u_char ier; if (bas->rclk == 0) bas->rclk = DEFAULT_RCLK; ns8250_param(bas, baudrate, databits, stopbits, parity); /* Disable all interrupt sources. */ /* * We use 0xe0 instead of 0xf0 as the mask because the XScale PXA * UARTs split the receive time-out interrupt bit out separately as * 0x10. This gets handled by ier_mask and ier_rxbits below. */ ier = uart_getreg(bas, REG_IER) & 0xe0; uart_setreg(bas, REG_IER, ier); uart_barrier(bas); /* Disable the FIFO (if present). */ uart_setreg(bas, REG_FCR, 0); uart_barrier(bas); /* Set RTS & DTR. */ uart_setreg(bas, REG_MCR, MCR_IE | MCR_RTS | MCR_DTR); uart_barrier(bas); ns8250_clrint(bas); } static void ns8250_term(struct uart_bas *bas) { /* Clear RTS & DTR. */ uart_setreg(bas, REG_MCR, MCR_IE); uart_barrier(bas); } static void ns8250_putc(struct uart_bas *bas, int c) { int limit; limit = 250000; while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0 && --limit) DELAY(4); uart_setreg(bas, REG_DATA, c); uart_barrier(bas); limit = 250000; while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) DELAY(4); } static int ns8250_rxready(struct uart_bas *bas) { return ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) != 0 ? 1 : 0); } static int ns8250_getc(struct uart_bas *bas, struct mtx *hwmtx) { int c; uart_lock(hwmtx); while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0) { uart_unlock(hwmtx); DELAY(4); uart_lock(hwmtx); } c = uart_getreg(bas, REG_DATA); uart_unlock(hwmtx); return (c); } static kobj_method_t ns8250_methods[] = { KOBJMETHOD(uart_attach, ns8250_bus_attach), KOBJMETHOD(uart_detach, ns8250_bus_detach), KOBJMETHOD(uart_flush, ns8250_bus_flush), KOBJMETHOD(uart_getsig, ns8250_bus_getsig), KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl), KOBJMETHOD(uart_ipend, ns8250_bus_ipend), KOBJMETHOD(uart_param, ns8250_bus_param), KOBJMETHOD(uart_probe, ns8250_bus_probe), KOBJMETHOD(uart_receive, ns8250_bus_receive), KOBJMETHOD(uart_setsig, ns8250_bus_setsig), KOBJMETHOD(uart_transmit, ns8250_bus_transmit), KOBJMETHOD(uart_grab, ns8250_bus_grab), KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab), { 0, 0 } }; struct uart_class uart_ns8250_class = { "ns8250", ns8250_methods, sizeof(struct ns8250_softc), .uc_ops = &uart_ns8250_ops, .uc_range = 8, .uc_rclk = DEFAULT_RCLK, .uc_rshift = 0 }; #ifdef FDT static struct ofw_compat_data compat_data[] = { {"ns16550", (uintptr_t)&uart_ns8250_class}, + {"snps,dw-apb-uart", (uintptr_t)&uart_ns8250_class}, {NULL, (uintptr_t)NULL}, }; UART_FDT_CLASS_AND_DEVICE(compat_data); #endif /* Use token-pasting to form SER_ and MSR_ named constants. */ #define SER(sig) SER_##sig #define SERD(sig) SER_D##sig #define MSR(sig) MSR_##sig #define MSRD(sig) MSR_D##sig /* * Detect signal changes using software delta detection. The previous state of * the signals is in 'var' the new hardware state is in 'msr', and 'sig' is the * short name (DCD, CTS, etc) of the signal bit being processed; 'var' gets the * new state of both the signal and the delta bits. */ #define SIGCHGSW(var, msr, sig) \ if ((msr) & MSR(sig)) { \ if ((var & SER(sig)) == 0) \ var |= SERD(sig) | SER(sig); \ } else { \ if ((var & SER(sig)) != 0) \ var = SERD(sig) | (var & ~SER(sig)); \ } /* * Detect signal changes using the hardware msr delta bits. This is currently * used only when PPS timing information is being captured using the "narrow * pulse" option. With a narrow PPS pulse the signal may not still be asserted * by time the interrupt handler is invoked. The hardware will latch the fact * that it changed in the delta bits. */ #define SIGCHGHW(var, msr, sig) \ if ((msr) & MSRD(sig)) { \ if (((msr) & MSR(sig)) != 0) \ var |= SERD(sig) | SER(sig); \ else \ var = SERD(sig) | (var & ~SER(sig)); \ } int ns8250_bus_attach(struct uart_softc *sc) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; unsigned int ivar; #ifdef FDT phandle_t node; pcell_t cell; #endif ns8250->busy_detect = 0; #ifdef FDT /* * Check whether uart requires to read USR reg when IIR_BUSY and * has broken txfifo. */ + ns8250->busy_detect = ofw_bus_is_compatible(sc->sc_dev, "snps,dw-apb-uart"); node = ofw_bus_get_node(sc->sc_dev); - if ((OF_getencprop(node, "busy-detect", &cell, sizeof(cell))) > 0) - ns8250->busy_detect = cell ? 1 : 0; + /* XXX: This is kept for a short time for compatibility with older device trees */ + if ((OF_getencprop(node, "busy-detect", &cell, sizeof(cell))) > 0 + && cell != 0) + ns8250->busy_detect = 1; if ((OF_getencprop(node, "broken-txfifo", &cell, sizeof(cell))) > 0) broken_txfifo = cell ? 1 : 0; #endif bas = &sc->sc_bas; ns8250->mcr = uart_getreg(bas, REG_MCR); ns8250->fcr = FCR_ENABLE; if (!resource_int_value("uart", device_get_unit(sc->sc_dev), "flags", &ivar)) { if (UART_FLAGS_FCR_RX_LOW(ivar)) ns8250->fcr |= FCR_RX_LOW; else if (UART_FLAGS_FCR_RX_MEDL(ivar)) ns8250->fcr |= FCR_RX_MEDL; else if (UART_FLAGS_FCR_RX_HIGH(ivar)) ns8250->fcr |= FCR_RX_HIGH; else ns8250->fcr |= FCR_RX_MEDH; } else ns8250->fcr |= FCR_RX_MEDH; /* Get IER mask */ ivar = 0xf0; resource_int_value("uart", device_get_unit(sc->sc_dev), "ier_mask", &ivar); ns8250->ier_mask = (uint8_t)(ivar & 0xff); /* Get IER RX interrupt bits */ ivar = IER_EMSC | IER_ERLS | IER_ERXRDY; resource_int_value("uart", device_get_unit(sc->sc_dev), "ier_rxbits", &ivar); ns8250->ier_rxbits = (uint8_t)(ivar & 0xff); uart_setreg(bas, REG_FCR, ns8250->fcr); uart_barrier(bas); ns8250_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); if (ns8250->mcr & MCR_DTR) sc->sc_hwsig |= SER_DTR; if (ns8250->mcr & MCR_RTS) sc->sc_hwsig |= SER_RTS; ns8250_bus_getsig(sc); ns8250_clrint(bas); ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; ns8250->ier |= ns8250->ier_rxbits; uart_setreg(bas, REG_IER, ns8250->ier); uart_barrier(bas); /* * Timing of the H/W access was changed with r253161 of uart_core.c * It has been observed that an ITE IT8513E would signal a break * condition with pretty much every character it received, unless * it had enough time to settle between ns8250_bus_attach() and * ns8250_bus_ipend() -- which it accidentally had before r253161. * It's not understood why the UART chip behaves this way and it * could very well be that the DELAY make the H/W work in the same * accidental manner as before. More analysis is warranted, but * at least now we fixed a known regression. */ DELAY(200); return (0); } int ns8250_bus_detach(struct uart_softc *sc) { struct ns8250_softc *ns8250; struct uart_bas *bas; u_char ier; ns8250 = (struct ns8250_softc *)sc; bas = &sc->sc_bas; ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; uart_setreg(bas, REG_IER, ier); uart_barrier(bas); ns8250_clrint(bas); return (0); } int ns8250_bus_flush(struct uart_softc *sc, int what) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; int error; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); if (sc->sc_rxfifosz > 1) { ns8250_flush(bas, what); uart_setreg(bas, REG_FCR, ns8250->fcr); uart_barrier(bas); error = 0; } else error = ns8250_drain(bas, what); uart_unlock(sc->sc_hwmtx); return (error); } int ns8250_bus_getsig(struct uart_softc *sc) { uint32_t old, sig; uint8_t msr; /* * The delta bits are reputed to be broken on some hardware, so use * software delta detection by default. Use the hardware delta bits * when capturing PPS pulses which are too narrow for software detection * to see the edges. Hardware delta for RI doesn't work like the * others, so always use software for it. Other threads may be changing * other (non-MSR) bits in sc_hwsig, so loop until it can succesfully * update without other changes happening. Note that the SIGCHGxx() * macros carefully preserve the delta bits when we have to loop several * times and a signal transitions between iterations. */ do { old = sc->sc_hwsig; sig = old; uart_lock(sc->sc_hwmtx); msr = uart_getreg(&sc->sc_bas, REG_MSR); uart_unlock(sc->sc_hwmtx); if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) { SIGCHGHW(sig, msr, DSR); SIGCHGHW(sig, msr, CTS); SIGCHGHW(sig, msr, DCD); } else { SIGCHGSW(sig, msr, DSR); SIGCHGSW(sig, msr, CTS); SIGCHGSW(sig, msr, DCD); } SIGCHGSW(sig, msr, RI); } while (!atomic_cmpset_32(&sc->sc_hwsig, old, sig & ~SER_MASK_DELTA)); return (sig); } int ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas; int baudrate, divisor, error; uint8_t efr, lcr; bas = &sc->sc_bas; error = 0; uart_lock(sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: lcr = uart_getreg(bas, REG_LCR); if (data) lcr |= LCR_SBREAK; else lcr &= ~LCR_SBREAK; uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_IFLOW: lcr = uart_getreg(bas, REG_LCR); uart_barrier(bas); uart_setreg(bas, REG_LCR, 0xbf); uart_barrier(bas); efr = uart_getreg(bas, REG_EFR); if (data) efr |= EFR_RTS; else efr &= ~EFR_RTS; uart_setreg(bas, REG_EFR, efr); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_OFLOW: lcr = uart_getreg(bas, REG_LCR); uart_barrier(bas); uart_setreg(bas, REG_LCR, 0xbf); uart_barrier(bas); efr = uart_getreg(bas, REG_EFR); if (data) efr |= EFR_CTS; else efr &= ~EFR_CTS; uart_setreg(bas, REG_EFR, efr); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_BAUD: lcr = uart_getreg(bas, REG_LCR); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; if (baudrate > 0) *(int*)data = baudrate; else error = ENXIO; break; default: error = EINVAL; break; } uart_unlock(sc->sc_hwmtx); return (error); } int ns8250_bus_ipend(struct uart_softc *sc) { struct uart_bas *bas; struct ns8250_softc *ns8250; int ipend; uint8_t iir, lsr; ns8250 = (struct ns8250_softc *)sc; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); iir = uart_getreg(bas, REG_IIR); if (ns8250->busy_detect && (iir & IIR_BUSY) == IIR_BUSY) { (void)uart_getreg(bas, DW_REG_USR); uart_unlock(sc->sc_hwmtx); return (0); } if (iir & IIR_NOPEND) { uart_unlock(sc->sc_hwmtx); return (0); } ipend = 0; if (iir & IIR_RXRDY) { lsr = uart_getreg(bas, REG_LSR); if (lsr & LSR_OE) ipend |= SER_INT_OVERRUN; if (lsr & LSR_BI) ipend |= SER_INT_BREAK; if (lsr & LSR_RXRDY) ipend |= SER_INT_RXREADY; } else { if (iir & IIR_TXRDY) { ipend |= SER_INT_TXIDLE; uart_setreg(bas, REG_IER, ns8250->ier); } else ipend |= SER_INT_SIGCHG; } if (ipend == 0) ns8250_clrint(bas); uart_unlock(sc->sc_hwmtx); return (ipend); } int ns8250_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { struct ns8250_softc *ns8250; struct uart_bas *bas; int error, limit; ns8250 = (struct ns8250_softc*)sc; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); /* * When using DW UART with BUSY detection it is necessary to wait * until all serial transfers are finished before manipulating the * line control. LCR will not be affected when UART is busy. */ if (ns8250->busy_detect != 0) { /* * Pick an arbitrary high limit to avoid getting stuck in * an infinite loop in case when the hardware is broken. */ limit = 10 * 1024; while (((uart_getreg(bas, DW_REG_USR) & USR_BUSY) != 0) && --limit) DELAY(4); if (limit <= 0) { /* UART appears to be stuck */ uart_unlock(sc->sc_hwmtx); return (EIO); } } error = ns8250_param(bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (error); } int ns8250_bus_probe(struct uart_softc *sc) { struct ns8250_softc *ns8250; struct uart_bas *bas; int count, delay, error, limit; uint8_t lsr, mcr, ier; ns8250 = (struct ns8250_softc *)sc; bas = &sc->sc_bas; error = ns8250_probe(bas); if (error) return (error); mcr = MCR_IE; if (sc->sc_sysdev == NULL) { /* By using ns8250_init() we also set DTR and RTS. */ ns8250_init(bas, 115200, 8, 1, UART_PARITY_NONE); } else mcr |= MCR_DTR | MCR_RTS; error = ns8250_drain(bas, UART_DRAIN_TRANSMITTER); if (error) return (error); /* * Set loopback mode. This avoids having garbage on the wire and * also allows us send and receive data. We set DTR and RTS to * avoid the possibility that automatic flow-control prevents * any data from being sent. */ uart_setreg(bas, REG_MCR, MCR_LOOPBACK | MCR_IE | MCR_DTR | MCR_RTS); uart_barrier(bas); /* * Enable FIFOs. And check that the UART has them. If not, we're * done. Since this is the first time we enable the FIFOs, we reset * them. */ uart_setreg(bas, REG_FCR, FCR_ENABLE); uart_barrier(bas); if (!(uart_getreg(bas, REG_IIR) & IIR_FIFO_MASK)) { /* * NS16450 or INS8250. We don't bother to differentiate * between them. They're too old to be interesting. */ uart_setreg(bas, REG_MCR, mcr); uart_barrier(bas); sc->sc_rxfifosz = sc->sc_txfifosz = 1; device_set_desc(sc->sc_dev, "8250 or 16450 or compatible"); return (0); } uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST); uart_barrier(bas); count = 0; delay = ns8250_delay(bas); /* We have FIFOs. Drain the transmitter and receiver. */ error = ns8250_drain(bas, UART_DRAIN_RECEIVER|UART_DRAIN_TRANSMITTER); if (error) { uart_setreg(bas, REG_MCR, mcr); uart_setreg(bas, REG_FCR, 0); uart_barrier(bas); goto describe; } /* * We should have a sufficiently clean "pipe" to determine the * size of the FIFOs. We send as much characters as is reasonable * and wait for the overflow bit in the LSR register to be * asserted, counting the characters as we send them. Based on * that count we know the FIFO size. */ do { uart_setreg(bas, REG_DATA, 0); uart_barrier(bas); count++; limit = 30; lsr = 0; /* * LSR bits are cleared upon read, so we must accumulate * them to be able to test LSR_OE below. */ while (((lsr |= uart_getreg(bas, REG_LSR)) & LSR_TEMT) == 0 && --limit) DELAY(delay); if (limit == 0) { ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; uart_setreg(bas, REG_IER, ier); uart_setreg(bas, REG_MCR, mcr); uart_setreg(bas, REG_FCR, 0); uart_barrier(bas); count = 0; goto describe; } } while ((lsr & LSR_OE) == 0 && count < 130); count--; uart_setreg(bas, REG_MCR, mcr); /* Reset FIFOs. */ ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); describe: if (count >= 14 && count <= 16) { sc->sc_rxfifosz = 16; device_set_desc(sc->sc_dev, "16550 or compatible"); } else if (count >= 28 && count <= 32) { sc->sc_rxfifosz = 32; device_set_desc(sc->sc_dev, "16650 or compatible"); } else if (count >= 56 && count <= 64) { sc->sc_rxfifosz = 64; device_set_desc(sc->sc_dev, "16750 or compatible"); } else if (count >= 112 && count <= 128) { sc->sc_rxfifosz = 128; device_set_desc(sc->sc_dev, "16950 or compatible"); } else { sc->sc_rxfifosz = 16; device_set_desc(sc->sc_dev, "Non-standard ns8250 class UART with FIFOs"); } /* * Force the Tx FIFO size to 16 bytes for now. We don't program the * Tx trigger. Also, we assume that all data has been sent when the * interrupt happens. */ sc->sc_txfifosz = 16; #if 0 /* * XXX there are some issues related to hardware flow control and * it's likely that uart(4) is the cause. This basicly needs more * investigation, but we avoid using for hardware flow control * until then. */ /* 16650s or higher have automatic flow control. */ if (sc->sc_rxfifosz > 16) { sc->sc_hwiflow = 1; sc->sc_hwoflow = 1; } #endif return (0); } int ns8250_bus_receive(struct uart_softc *sc) { struct uart_bas *bas; int xc; uint8_t lsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); lsr = uart_getreg(bas, REG_LSR); while (lsr & LSR_RXRDY) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } xc = uart_getreg(bas, REG_DATA); if (lsr & LSR_FE) xc |= UART_STAT_FRAMERR; if (lsr & LSR_PE) xc |= UART_STAT_PARERR; uart_rx_put(sc, xc); lsr = uart_getreg(bas, REG_LSR); } /* Discard everything left in the Rx FIFO. */ while (lsr & LSR_RXRDY) { (void)uart_getreg(bas, REG_DATA); uart_barrier(bas); lsr = uart_getreg(bas, REG_LSR); } uart_unlock(sc->sc_hwmtx); return (0); } int ns8250_bus_setsig(struct uart_softc *sc, int sig) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; uint32_t new, old; bas = &sc->sc_bas; do { old = sc->sc_hwsig; new = old; if (sig & SER_DDTR) { new = (new & ~SER_DTR) | (sig & (SER_DTR | SER_DDTR)); } if (sig & SER_DRTS) { new = (new & ~SER_RTS) | (sig & (SER_RTS | SER_DRTS)); } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); uart_lock(sc->sc_hwmtx); ns8250->mcr &= ~(MCR_DTR|MCR_RTS); if (new & SER_DTR) ns8250->mcr |= MCR_DTR; if (new & SER_RTS) ns8250->mcr |= MCR_RTS; uart_setreg(bas, REG_MCR, ns8250->mcr); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); return (0); } int ns8250_bus_transmit(struct uart_softc *sc) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; int i; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) ; uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY); uart_barrier(bas); for (i = 0; i < sc->sc_txdatasz; i++) { uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); uart_barrier(bas); } if (broken_txfifo) ns8250_drain(bas, UART_DRAIN_TRANSMITTER); else sc->sc_txbusy = 1; uart_unlock(sc->sc_hwmtx); if (broken_txfifo) uart_sched_softih(sc, SER_INT_TXIDLE); return (0); } void ns8250_bus_grab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; u_char ier; /* * turn off all interrupts to enter polling mode. Leave the * saved mask alone. We'll restore whatever it was in ungrab. * All pending interupt signals are reset when IER is set to 0. */ uart_lock(sc->sc_hwmtx); ier = uart_getreg(bas, REG_IER); uart_setreg(bas, REG_IER, ier & ns8250->ier_mask); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } void ns8250_bus_ungrab(struct uart_softc *sc) { struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas = &sc->sc_bas; /* * Restore previous interrupt mask */ uart_lock(sc->sc_hwmtx); uart_setreg(bas, REG_IER, ns8250->ier); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } Index: projects/release-pkg/sys/dev/usb/controller/ehci_mv.c =================================================================== --- projects/release-pkg/sys/dev/usb/controller/ehci_mv.c (revision 294447) +++ projects/release-pkg/sys/dev/usb/controller/ehci_mv.c (revision 294448) @@ -1,353 +1,363 @@ /*- * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * FDT attachment driver for the USB Enhanced Host Controller. */ #include __FBSDID("$FreeBSD$"); #include "opt_bus.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EHCI_VENDORID_MRVL 0x1286 #define EHCI_HC_DEVSTR "Marvell Integrated USB 2.0 controller" static device_attach_t mv_ehci_attach; static device_detach_t mv_ehci_detach; static int err_intr(void *arg); static struct resource *irq_err; static void *ih_err; /* EHCI HC regs start at this offset within USB range */ #define MV_USB_HOST_OFST 0x0100 #define USB_BRIDGE_INTR_CAUSE 0x210 #define USB_BRIDGE_INTR_MASK 0x214 #define USB_BRIDGE_ERR_ADDR 0x21C #define MV_USB_ADDR_DECODE_ERR (1 << 0) #define MV_USB_HOST_UNDERFLOW (1 << 1) #define MV_USB_HOST_OVERFLOW (1 << 2) #define MV_USB_DEVICE_UNDERFLOW (1 << 3) +static struct ofw_compat_data compat_data[] = { + {"mrvl,usb-ehci", true}, + {"marvell,orion-ehci", true}, + {NULL, false} +}; + static int mv_ehci_probe(device_t self) { if (!ofw_bus_status_okay(self)) return (ENXIO); - if (!ofw_bus_is_compatible(self, "mrvl,usb-ehci")) + if (!ofw_bus_search_compatible(self, compat_data)->ocd_data) return (ENXIO); device_set_desc(self, EHCI_HC_DEVSTR); return (BUS_PROBE_DEFAULT); } static int mv_ehci_attach(device_t self) { ehci_softc_t *sc = device_get_softc(self); bus_space_handle_t bsh; int err; int rid; /* initialise some bus fields */ sc->sc_bus.parent = self; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; sc->sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { return (ENOMEM); } rid = 0; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); bsh = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res) - MV_USB_HOST_OFST; /* * Marvell EHCI host controller registers start at certain offset * within the whole USB registers range, so create a subregion for the * host mode configuration purposes. */ if (bus_space_subregion(sc->sc_io_tag, bsh, MV_USB_HOST_OFST, sc->sc_io_size, &sc->sc_io_hdl) != 0) panic("%s: unable to subregion USB host registers", device_get_name(self)); rid = 0; - irq_err = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (irq_err == NULL) { - device_printf(self, "Could not allocate error irq\n"); - mv_ehci_detach(self); - return (ENXIO); + if (!ofw_bus_is_compatible(self, "marvell,orion-ehci")) { + irq_err = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (irq_err == NULL) { + device_printf(self, "Could not allocate error irq\n"); + mv_ehci_detach(self); + return (ENXIO); + } + rid = 1; } /* * Notice: Marvell EHCI controller has TWO interrupt lines, so make * sure to use the correct rid for the main one (controller interrupt) * -- refer to DTS for the right resource number to use here. */ - rid = 1; sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); goto error; } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); sprintf(sc->sc_vendor, "Marvell"); - err = bus_setup_intr(self, irq_err, INTR_TYPE_BIO, - err_intr, NULL, sc, &ih_err); - if (err) { - device_printf(self, "Could not setup error irq, %d\n", err); - ih_err = NULL; - goto error; + if (!ofw_bus_is_compatible(self, "marvell,orion-ehci")) { + err = bus_setup_intr(self, irq_err, INTR_TYPE_BIO, + err_intr, NULL, sc, &ih_err); + if (err) { + device_printf(self, "Could not setup error irq, %d\n", err); + ih_err = NULL; + goto error; + } } EWRITE4(sc, USB_BRIDGE_INTR_MASK, MV_USB_ADDR_DECODE_ERR | MV_USB_HOST_UNDERFLOW | MV_USB_HOST_OVERFLOW | MV_USB_DEVICE_UNDERFLOW); err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } /* * Workaround for Marvell integrated EHCI controller: reset of * the EHCI core clears the USBMODE register, which sets the core in * an undefined state (neither host nor agent), so it needs to be set * again for proper operation. * * Refer to errata document MV-S500832-00D.pdf (p. 5.24 GL USB-2) for * details. */ sc->sc_flags |= EHCI_SCFLG_SETMODE; if (bootverbose) device_printf(self, "5.24 GL USB-2 workaround enabled\n"); /* XXX all MV chips need it? */ sc->sc_flags |= EHCI_SCFLG_FORCESPEED | EHCI_SCFLG_NORESTERM; err = ehci_init(sc); if (!err) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(self, "USB init failed err=%d\n", err); goto error; } return (0); error: mv_ehci_detach(self); return (ENXIO); } static int mv_ehci_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); device_t bdev; int err; if (sc->sc_bus.bdev) { bdev = sc->sc_bus.bdev; device_detach(bdev); device_delete_child(self, bdev); } /* during module unload there are lots of children leftover */ device_delete_children(self); /* * disable interrupts that might have been switched on in mv_ehci_attach */ if (sc->sc_io_res) { EWRITE4(sc, USB_BRIDGE_INTR_MASK, 0); } if (sc->sc_irq_res && sc->sc_intr_hdl) { /* * only call ehci_detach() after ehci_init() */ ehci_detach(sc); err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); if (err) /* XXX or should we panic? */ device_printf(self, "Could not tear down irq, %d\n", err); sc->sc_intr_hdl = NULL; } if (irq_err && ih_err) { err = bus_teardown_intr(self, irq_err, ih_err); if (err) device_printf(self, "Could not tear down irq, %d\n", err); ih_err = NULL; } if (irq_err) { bus_release_resource(self, SYS_RES_IRQ, 0, irq_err); irq_err = NULL; } if (sc->sc_irq_res) { bus_release_resource(self, SYS_RES_IRQ, 1, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); sc->sc_io_res = NULL; } usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); return (0); } static int err_intr(void *arg) { ehci_softc_t *sc = arg; unsigned int cause; cause = EREAD4(sc, USB_BRIDGE_INTR_CAUSE); if (cause) { printf("USB error: "); if (cause & MV_USB_ADDR_DECODE_ERR) { uint32_t addr; addr = EREAD4(sc, USB_BRIDGE_ERR_ADDR); printf("address decoding error (addr=%#x)\n", addr); } if (cause & MV_USB_HOST_UNDERFLOW) printf("host underflow\n"); if (cause & MV_USB_HOST_OVERFLOW) printf("host overflow\n"); if (cause & MV_USB_DEVICE_UNDERFLOW) printf("device underflow\n"); if (cause & ~(MV_USB_ADDR_DECODE_ERR | MV_USB_HOST_UNDERFLOW | MV_USB_HOST_OVERFLOW | MV_USB_DEVICE_UNDERFLOW)) printf("unknown cause (cause=%#x)\n", cause); EWRITE4(sc, USB_BRIDGE_INTR_CAUSE, 0); } return (FILTER_HANDLED); } static device_method_t ehci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mv_ehci_probe), DEVMETHOD(device_attach, mv_ehci_attach), DEVMETHOD(device_detach, mv_ehci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ehci_driver = { "ehci", ehci_methods, sizeof(ehci_softc_t), }; static devclass_t ehci_devclass; DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); MODULE_DEPEND(ehci, usb, 1, 1, 1); Index: projects/release-pkg/sys/dev/xen/netfront/netfront.c =================================================================== --- projects/release-pkg/sys/dev/xen/netfront/netfront.c (revision 294447) +++ projects/release-pkg/sys/dev/xen/netfront/netfront.c (revision 294448) @@ -1,2037 +1,2355 @@ /*- * Copyright (c) 2004-2006 Kip Macy + * Copyright (c) 2015 Wei Liu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include - #include - #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xenbus_if.h" /* Features supported by all backends. TSO and LRO can be negotiated */ #define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) /* * Should the driver do LRO on the RX end * this can be toggled on the fly, but the * interface must be reset (down/up) for it * to take effect. */ static int xn_enable_lro = 1; TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); +/* + * Number of pairs of queues. + */ +static unsigned long xn_num_queues = 4; +TUNABLE_ULONG("hw.xn.num_queues", &xn_num_queues); + /** * \brief The maximum allowed data fragments in a single transmit * request. * * This limit is imposed by the backend driver. We assume here that * we are dealing with a Linux driver domain and have set our limit * to mirror the Linux MAX_SKB_FRAGS constant. */ #define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) #define RX_COPY_THRESHOLD 256 #define net_ratelimit() 0 +struct netfront_rxq; +struct netfront_txq; struct netfront_info; struct netfront_rx_info; -static void xn_txeof(struct netfront_info *); -static void xn_rxeof(struct netfront_info *); -static void network_alloc_rx_buffers(struct netfront_info *); +static void xn_txeof(struct netfront_txq *); +static void xn_rxeof(struct netfront_rxq *); +static void xn_alloc_rx_buffers(struct netfront_rxq *); -static void xn_tick_locked(struct netfront_info *); -static void xn_tick(void *); +static void xn_release_rx_bufs(struct netfront_rxq *); +static void xn_release_tx_bufs(struct netfront_txq *); -static void xn_intr(void *); +static void xn_rxq_intr(void *); +static void xn_txq_intr(void *); +static int xn_intr(void *); static inline int xn_count_frags(struct mbuf *m); -static int xn_assemble_tx_request(struct netfront_info *sc, - struct mbuf *m_head); -static void xn_start_locked(struct ifnet *); -static void xn_start(struct ifnet *); -static int xn_ioctl(struct ifnet *, u_long, caddr_t); +static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *); +static int xn_ioctl(struct ifnet *, u_long, caddr_t); static void xn_ifinit_locked(struct netfront_info *); static void xn_ifinit(void *); static void xn_stop(struct netfront_info *); static void xn_query_features(struct netfront_info *np); -static int xn_configure_features(struct netfront_info *np); -#ifdef notyet -static void xn_watchdog(struct ifnet *); -#endif - -#ifdef notyet -static void netfront_closing(device_t dev); -#endif +static int xn_configure_features(struct netfront_info *np); static void netif_free(struct netfront_info *info); static int netfront_detach(device_t dev); +static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *); +static int xn_txq_mq_start(struct ifnet *, struct mbuf *); + static int talk_to_backend(device_t dev, struct netfront_info *info); static int create_netdev(device_t dev); static void netif_disconnect_backend(struct netfront_info *info); -static int setup_device(device_t dev, struct netfront_info *info); -static void free_ring(int *ref, void *ring_ptr_ref); - -static int xn_ifmedia_upd(struct ifnet *ifp); +static int setup_device(device_t dev, struct netfront_info *info, + unsigned long); +static int xn_ifmedia_upd(struct ifnet *ifp); static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); -/* Xenolinux helper functions */ -int network_connect(struct netfront_info *); +int xn_connect(struct netfront_info *); -static void xn_free_rx_ring(struct netfront_info *); +static int xn_get_responses(struct netfront_rxq *, + struct netfront_rx_info *, RING_IDX, RING_IDX *, + struct mbuf **); -static void xn_free_tx_ring(struct netfront_info *); - -static int xennet_get_responses(struct netfront_info *np, - struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, - struct mbuf **list); - #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) #define INVALID_P2M_ENTRY (~0UL) -/* - * Mbuf pointers. We need these to keep track of the virtual addresses - * of our mbuf chains since we can only convert from virtual to physical, - * not the other way around. The size must track the free index arrays. - */ -struct xn_chain_data { - struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; - int xn_tx_chain_cnt; - struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; +struct xn_rx_stats +{ + u_long rx_packets; /* total packets received */ + u_long rx_bytes; /* total bytes received */ + u_long rx_errors; /* bad packets received */ }; -struct netfront_stats +struct xn_tx_stats { - u_long rx_packets; /* total packets received */ - u_long tx_packets; /* total packets transmitted */ - u_long rx_bytes; /* total bytes received */ - u_long tx_bytes; /* total bytes transmitted */ - u_long rx_errors; /* bad packets received */ - u_long tx_errors; /* packet transmit problems */ + u_long tx_packets; /* total packets transmitted */ + u_long tx_bytes; /* total bytes transmitted */ + u_long tx_errors; /* packet transmit problems */ }; -struct netfront_info { - struct ifnet *xn_ifp; - struct lro_ctrl xn_lro; +#define XN_QUEUE_NAME_LEN 8 /* xn{t,r}x_%u, allow for two digits */ +struct netfront_rxq { + struct netfront_info *info; + u_int id; + char name[XN_QUEUE_NAME_LEN]; + struct mtx lock; - struct netfront_stats stats; - u_int tx_full; + int ring_ref; + netif_rx_front_ring_t ring; + xen_intr_handle_t xen_intr_handle; - netif_tx_front_ring_t tx; - netif_rx_front_ring_t rx; + grant_ref_t gref_head; + grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; - struct mtx tx_lock; - struct mtx rx_lock; - struct mtx sc_lock; + struct mbuf *mbufs[NET_RX_RING_SIZE + 1]; + struct mbufq batch; /* batch queue */ + int target; - xen_intr_handle_t xen_intr_handle; - u_int carrier; - u_int maxfrags; + xen_pfn_t pfn_array[NET_RX_RING_SIZE]; + struct lro_ctrl lro; + + struct taskqueue *tq; + struct task intrtask; + + struct xn_rx_stats stats; +}; + +struct netfront_txq { + struct netfront_info *info; + u_int id; + char name[XN_QUEUE_NAME_LEN]; + struct mtx lock; + + int ring_ref; + netif_tx_front_ring_t ring; + xen_intr_handle_t xen_intr_handle; + + grant_ref_t gref_head; + grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; + + struct mbuf *mbufs[NET_TX_RING_SIZE + 1]; + int mbufs_cnt; + struct buf_ring *br; + + struct taskqueue *tq; + struct task intrtask; + struct task defrtask; + + bool full; + + struct xn_tx_stats stats; +}; + +struct netfront_info { + struct ifnet *xn_ifp; + + struct mtx sc_lock; + + u_int num_queues; + struct netfront_rxq *rxq; + struct netfront_txq *txq; + + u_int carrier; + u_int maxfrags; + /* Receive-ring batched refills. */ #define RX_MIN_TARGET 32 #define RX_MAX_TARGET NET_RX_RING_SIZE - int rx_min_target; - int rx_max_target; - int rx_target; + int rx_min_target; + int rx_max_target; - grant_ref_t gref_tx_head; - grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; - grant_ref_t gref_rx_head; - grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; - device_t xbdev; - int tx_ring_ref; - int rx_ring_ref; uint8_t mac[ETHER_ADDR_LEN]; - struct xn_chain_data xn_cdata; /* mbufs */ - struct mbufq xn_rx_batch; /* batch queue */ int xn_if_flags; - struct callout xn_stat_ch; - xen_pfn_t rx_pfn_array[NET_RX_RING_SIZE]; struct ifmedia sc_media; bool xn_resume; }; -#define rx_mbufs xn_cdata.xn_rx_chain -#define tx_mbufs xn_cdata.xn_tx_chain +struct netfront_rx_info { + struct netif_rx_response rx; + struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; +}; -#define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock) -#define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock) +#define XN_RX_LOCK(_q) mtx_lock(&(_q)->lock) +#define XN_RX_UNLOCK(_q) mtx_unlock(&(_q)->lock) -#define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock) -#define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock) +#define XN_TX_LOCK(_q) mtx_lock(&(_q)->lock) +#define XN_TX_TRYLOCK(_q) mtx_trylock(&(_q)->lock) +#define XN_TX_UNLOCK(_q) mtx_unlock(&(_q)->lock) #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); -#define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); -#define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); +#define XN_RX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); +#define XN_TX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); -struct netfront_rx_info { - struct netif_rx_response rx; - struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; -}; - #define netfront_carrier_on(netif) ((netif)->carrier = 1) #define netfront_carrier_off(netif) ((netif)->carrier = 0) #define netfront_carrier_ok(netif) ((netif)->carrier) /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ static inline void add_id_to_freelist(struct mbuf **list, uintptr_t id) { + KASSERT(id != 0, ("%s: the head item (0) must always be free.", __func__)); list[id] = list[0]; list[0] = (struct mbuf *)id; } static inline unsigned short get_id_from_freelist(struct mbuf **list) { uintptr_t id; id = (uintptr_t)list[0]; KASSERT(id != 0, ("%s: the head item (0) must always remain free.", __func__)); list[0] = list[id]; return (id); } static inline int -xennet_rxidx(RING_IDX idx) +xn_rxidx(RING_IDX idx) { + return idx & (NET_RX_RING_SIZE - 1); } static inline struct mbuf * -xennet_get_rx_mbuf(struct netfront_info *np, RING_IDX ri) +xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri) { - int i = xennet_rxidx(ri); + int i; struct mbuf *m; - m = np->rx_mbufs[i]; - np->rx_mbufs[i] = NULL; + i = xn_rxidx(ri); + m = rxq->mbufs[i]; + rxq->mbufs[i] = NULL; return (m); } static inline grant_ref_t -xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) +xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri) { - int i = xennet_rxidx(ri); - grant_ref_t ref = np->grant_rx_ref[i]; + int i = xn_rxidx(ri); + grant_ref_t ref = rxq->grant_ref[i]; + KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); - np->grant_rx_ref[i] = GRANT_REF_INVALID; - return ref; + rxq->grant_ref[i] = GRANT_REF_INVALID; + return (ref); } #define IPRINTK(fmt, args...) \ printf("[XEN] " fmt, ##args) #ifdef INVARIANTS #define WPRINTK(fmt, args...) \ printf("[XEN] " fmt, ##args) #else #define WPRINTK(fmt, args...) #endif #ifdef DEBUG #define DPRINTK(fmt, args...) \ printf("[XEN] %s: " fmt, __func__, ##args) #else #define DPRINTK(fmt, args...) #endif /** * Read the 'mac' node at the given device's node in the store, and parse that * as colon-separated octets, placing result the given mac array. mac must be * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). * Return 0 on success, or errno on error. */ static int xen_net_read_mac(device_t dev, uint8_t mac[]) { int error, i; char *s, *e, *macstr; const char *path; path = xenbus_get_node(dev); error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); if (error == ENOENT) { /* * Deal with missing mac XenStore nodes on devices with * HVM emulation (the 'ioemu' configuration attribute) * enabled. * * The HVM emulator may execute in a stub device model * domain which lacks the permission, only given to Dom0, * to update the guest's XenStore tree. For this reason, * the HVM emulator doesn't even attempt to write the * front-side mac node, even when operating in Dom0. * However, there should always be a mac listed in the * backend tree. Fallback to this version if our query * of the front side XenStore location doesn't find * anything. */ path = xenbus_get_otherend_path(dev); error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); } if (error != 0) { xenbus_dev_fatal(dev, error, "parsing %s/mac", path); return (error); } s = macstr; for (i = 0; i < ETHER_ADDR_LEN; i++) { mac[i] = strtoul(s, &e, 16); if (s == e || (e[0] != ':' && e[0] != 0)) { free(macstr, M_XENBUS); return (ENOENT); } s = &e[1]; } free(macstr, M_XENBUS); return (0); } /** * Entry point to this code when a new device is created. Allocate the basic * structures and the ring buffers for communication with the backend, and * inform the backend of the appropriate details for those. Switch to * Connected state. */ static int netfront_probe(device_t dev) { if (xen_hvm_domain() && xen_disable_pv_nics != 0) return (ENXIO); if (!strcmp(xenbus_get_type(dev), "vif")) { device_set_desc(dev, "Virtual Network Interface"); return (0); } return (ENXIO); } static int netfront_attach(device_t dev) { int err; err = create_netdev(dev); - if (err) { + if (err != 0) { xenbus_dev_fatal(dev, err, "creating netdev"); return (err); } SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "enable_lro", CTLFLAG_RW, &xn_enable_lro, 0, "Large Receive Offload"); + SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "num_queues", CTLFLAG_RD, + &xn_num_queues, "Number of pairs of queues"); + return (0); } static int netfront_suspend(device_t dev) { - struct netfront_info *info = device_get_softc(dev); + struct netfront_info *np = device_get_softc(dev); + u_int i; - XN_RX_LOCK(info); - XN_TX_LOCK(info); - netfront_carrier_off(info); - XN_TX_UNLOCK(info); - XN_RX_UNLOCK(info); + for (i = 0; i < np->num_queues; i++) { + XN_RX_LOCK(&np->rxq[i]); + XN_TX_LOCK(&np->txq[i]); + } + netfront_carrier_off(np); + for (i = 0; i < np->num_queues; i++) { + XN_RX_UNLOCK(&np->rxq[i]); + XN_TX_UNLOCK(&np->txq[i]); + } return (0); } /** * We are reconnecting to the backend, due to a suspend/resume, or a backend * driver restart. We tear down our netif structure and recreate it, but * leave the device-layer structures intact so that this is transparent to the * rest of the kernel. */ static int netfront_resume(device_t dev) { struct netfront_info *info = device_get_softc(dev); info->xn_resume = true; netif_disconnect_backend(info); return (0); } +static int +write_queue_xenstore_keys(device_t dev, + struct netfront_rxq *rxq, + struct netfront_txq *txq, + struct xs_transaction *xst, bool hierarchy) +{ + int err; + const char *message; + const char *node = xenbus_get_node(dev); + char *path; + size_t path_size; + + KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids")); + /* Split event channel support is not yet there. */ + KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle, + ("Split event channels are not supported")); + + if (hierarchy) { + path_size = strlen(node) + 10; + path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); + snprintf(path, path_size, "%s/queue-%u", node, rxq->id); + } else { + path_size = strlen(node) + 1; + path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); + snprintf(path, path_size, "%s", node); + } + + err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref); + if (err != 0) { + message = "writing tx ring-ref"; + goto error; + } + err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref); + if (err != 0) { + message = "writing rx ring-ref"; + goto error; + } + err = xs_printf(*xst, path, "event-channel", "%u", + xen_intr_port(rxq->xen_intr_handle)); + if (err != 0) { + message = "writing event-channel"; + goto error; + } + + free(path, M_DEVBUF); + + return (0); + +error: + free(path, M_DEVBUF); + xenbus_dev_fatal(dev, err, "%s", message); + + return (err); +} + /* Common code used when first setting up, and when resuming. */ static int talk_to_backend(device_t dev, struct netfront_info *info) { const char *message; struct xs_transaction xst; const char *node = xenbus_get_node(dev); int err; + unsigned long num_queues, max_queues = 0; + unsigned int i; err = xen_net_read_mac(dev, info->mac); - if (err) { + if (err != 0) { xenbus_dev_fatal(dev, err, "parsing %s/mac", node); goto out; } - /* Create shared ring, alloc event channel. */ - err = setup_device(dev, info); - if (err) + err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev), + "multi-queue-max-queues", NULL, "%lu", &max_queues); + if (err != 0) + max_queues = 1; + num_queues = xn_num_queues; + if (num_queues > max_queues) + num_queues = max_queues; + + err = setup_device(dev, info, num_queues); + if (err != 0) goto out; again: err = xs_transaction_start(&xst); - if (err) { + if (err != 0) { xenbus_dev_fatal(dev, err, "starting transaction"); - goto destroy_ring; + goto free; } - err = xs_printf(xst, node, "tx-ring-ref","%u", - info->tx_ring_ref); - if (err) { - message = "writing tx ring-ref"; - goto abort_transaction; + + if (info->num_queues == 1) { + err = write_queue_xenstore_keys(dev, &info->rxq[0], + &info->txq[0], &xst, false); + if (err != 0) + goto abort_transaction_no_def_error; + } else { + err = xs_printf(xst, node, "multi-queue-num-queues", + "%u", info->num_queues); + if (err != 0) { + message = "writing multi-queue-num-queues"; + goto abort_transaction; + } + + for (i = 0; i < info->num_queues; i++) { + err = write_queue_xenstore_keys(dev, &info->rxq[i], + &info->txq[i], &xst, true); + if (err != 0) + goto abort_transaction_no_def_error; + } } - err = xs_printf(xst, node, "rx-ring-ref","%u", - info->rx_ring_ref); - if (err) { - message = "writing rx ring-ref"; - goto abort_transaction; - } - err = xs_printf(xst, node, - "event-channel", "%u", - xen_intr_port(info->xen_intr_handle)); - if (err) { - message = "writing event-channel"; - goto abort_transaction; - } + err = xs_printf(xst, node, "request-rx-copy", "%u", 1); - if (err) { + if (err != 0) { message = "writing request-rx-copy"; goto abort_transaction; } err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); - if (err) { + if (err != 0) { message = "writing feature-rx-notify"; goto abort_transaction; } err = xs_printf(xst, node, "feature-sg", "%d", 1); - if (err) { + if (err != 0) { message = "writing feature-sg"; goto abort_transaction; } err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); - if (err) { + if (err != 0) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } err = xs_transaction_end(xst, 0); - if (err) { + if (err != 0) { if (err == EAGAIN) goto again; xenbus_dev_fatal(dev, err, "completing transaction"); - goto destroy_ring; + goto free; } return 0; abort_transaction: - xs_transaction_end(xst, 1); xenbus_dev_fatal(dev, err, "%s", message); - destroy_ring: + abort_transaction_no_def_error: + xs_transaction_end(xst, 1); + free: netif_free(info); out: - return err; + return (err); } +static void +xn_rxq_tq_intr(void *xrxq, int pending) +{ + struct netfront_rxq *rxq = xrxq; + + XN_RX_LOCK(rxq); + xn_rxeof(rxq); + XN_RX_UNLOCK(rxq); +} + +static void +xn_txq_start(struct netfront_txq *txq) +{ + struct netfront_info *np = txq->info; + struct ifnet *ifp = np->xn_ifp; + + XN_TX_LOCK_ASSERT(txq); + if (!drbr_empty(ifp, txq->br)) + xn_txq_mq_start_locked(txq, NULL); +} + +static void +xn_txq_tq_intr(void *xtxq, int pending) +{ + struct netfront_txq *txq = xtxq; + + XN_TX_LOCK(txq); + if (RING_HAS_UNCONSUMED_RESPONSES(&txq->ring)) + xn_txeof(txq); + xn_txq_start(txq); + XN_TX_UNLOCK(txq); +} + +static void +xn_txq_tq_deferred(void *xtxq, int pending) +{ + struct netfront_txq *txq = xtxq; + + XN_TX_LOCK(txq); + xn_txq_start(txq); + XN_TX_UNLOCK(txq); +} + +static void +disconnect_rxq(struct netfront_rxq *rxq) +{ + + xn_release_rx_bufs(rxq); + gnttab_free_grant_references(rxq->gref_head); + gnttab_end_foreign_access_ref(rxq->ring_ref); + /* + * No split event channel support at the moment, handle will + * be unbound in tx. So no need to call xen_intr_unbind here, + * but we do want to reset the handler to 0. + */ + rxq->xen_intr_handle = 0; +} + +static void +destroy_rxq(struct netfront_rxq *rxq) +{ + + free(rxq->ring.sring, M_DEVBUF); + taskqueue_drain_all(rxq->tq); + taskqueue_free(rxq->tq); +} + +static void +destroy_rxqs(struct netfront_info *np) +{ + int i; + + for (i = 0; i < np->num_queues; i++) + destroy_rxq(&np->rxq[i]); + + free(np->rxq, M_DEVBUF); + np->rxq = NULL; +} + static int -setup_device(device_t dev, struct netfront_info *info) +setup_rxqs(device_t dev, struct netfront_info *info, + unsigned long num_queues) { - netif_tx_sring_t *txs; - netif_rx_sring_t *rxs; + int q, i; int error; + netif_rx_sring_t *rxs; + struct netfront_rxq *rxq; - info->tx_ring_ref = GRANT_REF_INVALID; - info->rx_ring_ref = GRANT_REF_INVALID; - info->rx.sring = NULL; - info->tx.sring = NULL; + info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues, + M_DEVBUF, M_WAITOK|M_ZERO); - txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); - if (!txs) { - error = ENOMEM; - xenbus_dev_fatal(dev, error, "allocating tx ring page"); - goto fail; + for (q = 0; q < num_queues; q++) { + rxq = &info->rxq[q]; + + rxq->id = q; + rxq->info = info; + rxq->target = RX_MIN_TARGET; + rxq->ring_ref = GRANT_REF_INVALID; + rxq->ring.sring = NULL; + snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q); + mtx_init(&rxq->lock, rxq->name, "netfront receive lock", + MTX_DEF); + + for (i = 0; i <= NET_RX_RING_SIZE; i++) { + rxq->mbufs[i] = NULL; + rxq->grant_ref[i] = GRANT_REF_INVALID; + } + + mbufq_init(&rxq->batch, INT_MAX); + + /* Start resources allocation */ + + if (gnttab_alloc_grant_references(RX_MAX_TARGET, + &rxq->gref_head) != 0) { + device_printf(dev, "allocating rx gref"); + error = ENOMEM; + goto fail; + } + + rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, + M_WAITOK|M_ZERO); + SHARED_RING_INIT(rxs); + FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE); + + error = xenbus_grant_ring(dev, virt_to_mfn(rxs), + &rxq->ring_ref); + if (error != 0) { + device_printf(dev, "granting rx ring page"); + goto fail_grant_ring; + } + + TASK_INIT(&rxq->intrtask, 0, xn_rxq_tq_intr, rxq); + rxq->tq = taskqueue_create_fast(rxq->name, M_WAITOK, + taskqueue_thread_enqueue, &rxq->tq); + + error = taskqueue_start_threads(&rxq->tq, 1, PI_NET, + "%s rxq %d", device_get_nameunit(dev), rxq->id); + if (error != 0) { + device_printf(dev, "failed to start rx taskq %d\n", + rxq->id); + goto fail_start_thread; + } } - SHARED_RING_INIT(txs); - FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); - error = xenbus_grant_ring(dev, virt_to_mfn(txs), &info->tx_ring_ref); - if (error) - goto fail; - rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); - if (!rxs) { - error = ENOMEM; - xenbus_dev_fatal(dev, error, "allocating rx ring page"); - goto fail; + return (0); + +fail_start_thread: + gnttab_end_foreign_access_ref(rxq->ring_ref); + taskqueue_drain_all(rxq->tq); + taskqueue_free(rxq->tq); +fail_grant_ring: + gnttab_free_grant_references(rxq->gref_head); + free(rxq->ring.sring, M_DEVBUF); +fail: + for (; q >= 0; q--) { + disconnect_rxq(&info->rxq[q]); + destroy_rxq(&info->rxq[q]); } - SHARED_RING_INIT(rxs); - FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); - error = xenbus_grant_ring(dev, virt_to_mfn(rxs), &info->rx_ring_ref); - if (error) - goto fail; + free(info->rxq, M_DEVBUF); + return (error); +} - error = xen_intr_alloc_and_bind_local_port(dev, - xenbus_get_otherend_id(dev), /*filter*/NULL, xn_intr, info, - INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, &info->xen_intr_handle); +static void +disconnect_txq(struct netfront_txq *txq) +{ - if (error) { - xenbus_dev_fatal(dev, error, - "xen_intr_alloc_and_bind_local_port failed"); - goto fail; + xn_release_tx_bufs(txq); + gnttab_free_grant_references(txq->gref_head); + gnttab_end_foreign_access_ref(txq->ring_ref); + xen_intr_unbind(&txq->xen_intr_handle); +} + +static void +destroy_txq(struct netfront_txq *txq) +{ + + free(txq->ring.sring, M_DEVBUF); + buf_ring_free(txq->br, M_DEVBUF); + taskqueue_drain_all(txq->tq); + taskqueue_free(txq->tq); +} + +static void +destroy_txqs(struct netfront_info *np) +{ + int i; + + for (i = 0; i < np->num_queues; i++) + destroy_txq(&np->txq[i]); + + free(np->txq, M_DEVBUF); + np->txq = NULL; +} + +static int +setup_txqs(device_t dev, struct netfront_info *info, + unsigned long num_queues) +{ + int q, i; + int error; + netif_tx_sring_t *txs; + struct netfront_txq *txq; + + info->txq = malloc(sizeof(struct netfront_txq) * num_queues, + M_DEVBUF, M_WAITOK|M_ZERO); + + for (q = 0; q < num_queues; q++) { + txq = &info->txq[q]; + + txq->id = q; + txq->info = info; + + txq->ring_ref = GRANT_REF_INVALID; + txq->ring.sring = NULL; + + snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q); + + mtx_init(&txq->lock, txq->name, "netfront transmit lock", + MTX_DEF); + + for (i = 0; i <= NET_TX_RING_SIZE; i++) { + txq->mbufs[i] = (void *) ((u_long) i+1); + txq->grant_ref[i] = GRANT_REF_INVALID; + } + txq->mbufs[NET_TX_RING_SIZE] = (void *)0; + + /* Start resources allocation. */ + + if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, + &txq->gref_head) != 0) { + device_printf(dev, "failed to allocate tx grant refs\n"); + error = ENOMEM; + goto fail; + } + + txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, + M_WAITOK|M_ZERO); + SHARED_RING_INIT(txs); + FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE); + + error = xenbus_grant_ring(dev, virt_to_mfn(txs), + &txq->ring_ref); + if (error != 0) { + device_printf(dev, "failed to grant tx ring\n"); + goto fail_grant_ring; + } + + txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF, + M_WAITOK, &txq->lock); + TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq); + TASK_INIT(&txq->intrtask, 0, xn_txq_tq_intr, txq); + + txq->tq = taskqueue_create_fast(txq->name, M_WAITOK, + taskqueue_thread_enqueue, &txq->tq); + + error = taskqueue_start_threads(&txq->tq, 1, PI_NET, + "%s txq %d", device_get_nameunit(dev), txq->id); + if (error != 0) { + device_printf(dev, "failed to start tx taskq %d\n", + txq->id); + goto fail_start_thread; + } + + error = xen_intr_alloc_and_bind_local_port(dev, + xenbus_get_otherend_id(dev), xn_intr, /* handler */ NULL, + &info->txq[q], + INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, + &txq->xen_intr_handle); + + if (error != 0) { + device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n"); + goto fail_bind_port; + } } return (0); - fail: - netif_free(info); +fail_bind_port: + taskqueue_drain_all(txq->tq); +fail_start_thread: + gnttab_free_grant_references(txq->gref_head); + free(txq->ring.sring, M_DEVBUF); + gnttab_end_foreign_access_ref(txq->ring_ref); + buf_ring_free(txq->br, M_DEVBUF); + taskqueue_free(txq->tq); +fail_grant_ring: + gnttab_free_grant_references(txq->gref_head); + free(txq->ring.sring, M_DEVBUF); +fail: + for (; q >= 0; q--) { + disconnect_txq(&info->txq[q]); + destroy_txq(&info->txq[q]); + } + + free(info->txq, M_DEVBUF); return (error); } +static int +setup_device(device_t dev, struct netfront_info *info, + unsigned long num_queues) +{ + int error; + int q; + + if (info->txq) + destroy_txqs(info); + + if (info->rxq) + destroy_rxqs(info); + + info->num_queues = 0; + + error = setup_rxqs(dev, info, num_queues); + if (error != 0) + goto out; + error = setup_txqs(dev, info, num_queues); + if (error != 0) + goto out; + + info->num_queues = num_queues; + + /* No split event channel at the moment. */ + for (q = 0; q < num_queues; q++) + info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle; + + return (0); + +out: + KASSERT(error != 0, ("Error path taken without providing an error code")); + return (error); +} + #ifdef INET /** * If this interface has an ipv4 address, send an arp for it. This * helps to get the network going again after migrating hosts. */ static void netfront_send_fake_arp(device_t dev, struct netfront_info *info) { struct ifnet *ifp; struct ifaddr *ifa; ifp = info->xn_ifp; TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) { arp_ifinit(ifp, ifa); } } } #endif /** * Callback received when the backend's state changes. */ static void netfront_backend_changed(device_t dev, XenbusState newstate) { struct netfront_info *sc = device_get_softc(dev); DPRINTK("newstate=%d\n", newstate); switch (newstate) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: case XenbusStateClosed: case XenbusStateReconfigured: case XenbusStateReconfiguring: break; case XenbusStateInitWait: if (xenbus_get_state(dev) != XenbusStateInitialising) break; - if (network_connect(sc) != 0) + if (xn_connect(sc) != 0) break; xenbus_set_state(dev, XenbusStateConnected); break; case XenbusStateClosing: xenbus_set_state(dev, XenbusStateClosed); break; case XenbusStateConnected: #ifdef INET netfront_send_fake_arp(dev, sc); #endif break; } } -static void -xn_free_rx_ring(struct netfront_info *sc) -{ -#if 0 - int i; - - for (i = 0; i < NET_RX_RING_SIZE; i++) { - if (sc->xn_cdata.rx_mbufs[i] != NULL) { - m_freem(sc->rx_mbufs[i]); - sc->rx_mbufs[i] = NULL; - } - } - - sc->rx.rsp_cons = 0; - sc->xn_rx_if->req_prod = 0; - sc->xn_rx_if->event = sc->rx.rsp_cons ; -#endif -} - -static void -xn_free_tx_ring(struct netfront_info *sc) -{ -#if 0 - int i; - - for (i = 0; i < NET_TX_RING_SIZE; i++) { - if (sc->tx_mbufs[i] != NULL) { - m_freem(sc->tx_mbufs[i]); - sc->xn_cdata.xn_tx_chain[i] = NULL; - } - } - - return; -#endif -} - /** * \brief Verify that there is sufficient space in the Tx ring * buffer for a maximally sized request to be enqueued. * * A transmit request requires a transmit descriptor for each packet * fragment, plus up to 2 entries for "options" (e.g. TSO). */ static inline int -xn_tx_slot_available(struct netfront_info *np) +xn_tx_slot_available(struct netfront_txq *txq) { - return (RING_FREE_REQUESTS(&np->tx) > (MAX_TX_REQ_FRAGS + 2)); + + return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2)); } static void -netif_release_tx_bufs(struct netfront_info *np) +xn_release_tx_bufs(struct netfront_txq *txq) { int i; for (i = 1; i <= NET_TX_RING_SIZE; i++) { struct mbuf *m; - m = np->tx_mbufs[i]; + m = txq->mbufs[i]; /* * We assume that no kernel addresses are * less than NET_TX_RING_SIZE. Any entry * in the table that is below this number * must be an index from free-list tracking. */ if (((uintptr_t)m) <= NET_TX_RING_SIZE) continue; - gnttab_end_foreign_access_ref(np->grant_tx_ref[i]); - gnttab_release_grant_reference(&np->gref_tx_head, - np->grant_tx_ref[i]); - np->grant_tx_ref[i] = GRANT_REF_INVALID; - add_id_to_freelist(np->tx_mbufs, i); - np->xn_cdata.xn_tx_chain_cnt--; - if (np->xn_cdata.xn_tx_chain_cnt < 0) { + gnttab_end_foreign_access_ref(txq->grant_ref[i]); + gnttab_release_grant_reference(&txq->gref_head, + txq->grant_ref[i]); + txq->grant_ref[i] = GRANT_REF_INVALID; + add_id_to_freelist(txq->mbufs, i); + txq->mbufs_cnt--; + if (txq->mbufs_cnt < 0) { panic("%s: tx_chain_cnt must be >= 0", __func__); } m_free(m); } } static void -network_alloc_rx_buffers(struct netfront_info *sc) +xn_alloc_rx_buffers(struct netfront_rxq *rxq) { - int otherend_id = xenbus_get_otherend_id(sc->xbdev); + struct netfront_info *np = rxq->info; + int otherend_id = xenbus_get_otherend_id(np->xbdev); unsigned short id; struct mbuf *m_new; int i, batch_target, notify; RING_IDX req_prod; grant_ref_t ref; netif_rx_request_t *req; vm_offset_t vaddr; u_long pfn; - req_prod = sc->rx.req_prod_pvt; + req_prod = rxq->ring.req_prod_pvt; - if (__predict_false(sc->carrier == 0)) + if (__predict_false(np->carrier == 0)) return; /* * Allocate mbufs greedily, even though we batch updates to the * receive ring. This creates a less bursty demand on the memory * allocator, and so should reduce the chance of failed allocation * requests both for ourself and for other kernel subsystems. * * Here we attempt to maintain rx_target buffers in flight, counting * buffers that we have yet to process in the receive ring. */ - batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); - for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) { + batch_target = rxq->target - (req_prod - rxq->ring.rsp_cons); + for (i = mbufq_len(&rxq->batch); i < batch_target; i++) { m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); if (m_new == NULL) { if (i != 0) goto refill; - /* - * XXX set timer - */ + /* XXX set timer */ break; } m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; /* queue the mbufs allocated */ - (void )mbufq_enqueue(&sc->xn_rx_batch, m_new); + mbufq_enqueue(&rxq->batch, m_new); } /* * If we've allocated at least half of our target number of entries, * submit them to the backend - we have enough to make the overhead * of submission worthwhile. Otherwise wait for more mbufs and * request entries to become available. */ - if (i < (sc->rx_target/2)) { - if (req_prod >sc->rx.sring->req_prod) + if (i < (rxq->target/2)) { + if (req_prod > rxq->ring.sring->req_prod) goto push; return; } /* * Double floating fill target if we risked having the backend * run out of empty buffers for receive traffic. We define "running * low" as having less than a fourth of our target buffers free * at the time we refilled the queue. */ - if ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) { - sc->rx_target *= 2; - if (sc->rx_target > sc->rx_max_target) - sc->rx_target = sc->rx_max_target; + if ((req_prod - rxq->ring.sring->rsp_prod) < (rxq->target / 4)) { + rxq->target *= 2; + if (rxq->target > np->rx_max_target) + rxq->target = np->rx_max_target; } refill: for (i = 0; ; i++) { - if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL) + if ((m_new = mbufq_dequeue(&rxq->batch)) == NULL) break; m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)( vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); - id = xennet_rxidx(req_prod + i); + id = xn_rxidx(req_prod + i); - KASSERT(sc->rx_mbufs[id] == NULL, ("non-NULL xm_rx_chain")); - sc->rx_mbufs[id] = m_new; + KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain")); + rxq->mbufs[id] = m_new; - ref = gnttab_claim_grant_reference(&sc->gref_rx_head); + ref = gnttab_claim_grant_reference(&rxq->gref_head); KASSERT(ref != GNTTAB_LIST_END, ("reserved grant references exhuasted")); - sc->grant_rx_ref[id] = ref; + rxq->grant_ref[id] = ref; vaddr = mtod(m_new, vm_offset_t); pfn = vtophys(vaddr) >> PAGE_SHIFT; - req = RING_GET_REQUEST(&sc->rx, req_prod + i); + req = RING_GET_REQUEST(&rxq->ring, req_prod + i); gnttab_grant_foreign_access_ref(ref, otherend_id, pfn, 0); req->id = id; req->gref = ref; - sc->rx_pfn_array[i] = + rxq->pfn_array[i] = vtophys(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; } KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ - KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed")); + KASSERT(mbufq_len(&rxq->batch) == 0, ("not all mbufs processed")); /* * We may have allocated buffers which have entries outstanding * in the page * update queue -- make sure we flush those first! */ wmb(); /* Above is a suitable barrier to ensure backend will see requests. */ - sc->rx.req_prod_pvt = req_prod + i; + rxq->ring.req_prod_pvt = req_prod + i; push: - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify); + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify); if (notify) - xen_intr_signal(sc->xen_intr_handle); + xen_intr_signal(rxq->xen_intr_handle); } static void -xn_rxeof(struct netfront_info *np) +xn_release_rx_bufs(struct netfront_rxq *rxq) { + int i, ref; + struct mbuf *m; + + for (i = 0; i < NET_RX_RING_SIZE; i++) { + m = rxq->mbufs[i]; + + if (m == NULL) + continue; + + ref = rxq->grant_ref[i]; + if (ref == GRANT_REF_INVALID) + continue; + + gnttab_end_foreign_access_ref(ref); + gnttab_release_grant_reference(&rxq->gref_head, ref); + rxq->mbufs[i] = NULL; + rxq->grant_ref[i] = GRANT_REF_INVALID; + m_freem(m); + } +} + +static void +xn_rxeof(struct netfront_rxq *rxq) +{ struct ifnet *ifp; + struct netfront_info *np = rxq->info; #if (defined(INET) || defined(INET6)) - struct lro_ctrl *lro = &np->xn_lro; + struct lro_ctrl *lro = &rxq->lro; struct lro_entry *queued; #endif struct netfront_rx_info rinfo; struct netif_rx_response *rx = &rinfo.rx; struct netif_extra_info *extras = rinfo.extras; RING_IDX i, rp; struct mbuf *m; - struct mbufq rxq, errq; + struct mbufq mbufq_rxq, mbufq_errq; int err, work_to_do; do { - XN_RX_LOCK_ASSERT(np); + XN_RX_LOCK_ASSERT(rxq); if (!netfront_carrier_ok(np)) return; /* XXX: there should be some sane limit. */ - mbufq_init(&errq, INT_MAX); - mbufq_init(&rxq, INT_MAX); + mbufq_init(&mbufq_errq, INT_MAX); + mbufq_init(&mbufq_rxq, INT_MAX); ifp = np->xn_ifp; - rp = np->rx.sring->rsp_prod; + rp = rxq->ring.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - i = np->rx.rsp_cons; + i = rxq->ring.rsp_cons; while ((i != rp)) { - memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); + memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx)); memset(extras, 0, sizeof(rinfo.extras)); m = NULL; - err = xennet_get_responses(np, &rinfo, rp, &i, &m); + err = xn_get_responses(rxq, &rinfo, rp, &i, &m); if (__predict_false(err)) { if (m) - (void )mbufq_enqueue(&errq, m); - np->stats.rx_errors++; + (void )mbufq_enqueue(&mbufq_errq, m); + rxq->stats.rx_errors++; continue; } m->m_pkthdr.rcvif = ifp; if ( rx->flags & NETRXF_data_validated ) { /* Tell the stack the checksums are okay */ /* * XXX this isn't necessarily the case - need to add * check */ m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR); m->m_pkthdr.csum_data = 0xffff; } - np->stats.rx_packets++; - np->stats.rx_bytes += m->m_pkthdr.len; + rxq->stats.rx_packets++; + rxq->stats.rx_bytes += m->m_pkthdr.len; - (void )mbufq_enqueue(&rxq, m); - np->rx.rsp_cons = i; + (void )mbufq_enqueue(&mbufq_rxq, m); + rxq->ring.rsp_cons = i; } - mbufq_drain(&errq); + mbufq_drain(&mbufq_errq); /* * Process all the mbufs after the remapping is complete. * Break the mbuf chain first though. */ - while ((m = mbufq_dequeue(&rxq)) != NULL) { + while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) { if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); - /* - * Do we really need to drop the rx lock? - */ - XN_RX_UNLOCK(np); + /* XXX: Do we really need to drop the rx lock? */ + XN_RX_UNLOCK(rxq); #if (defined(INET) || defined(INET6)) /* Use LRO if possible */ if ((ifp->if_capenable & IFCAP_LRO) == 0 || lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { /* * If LRO fails, pass up to the stack * directly. */ (*ifp->if_input)(ifp, m); } #else (*ifp->if_input)(ifp, m); #endif - XN_RX_LOCK(np); + + XN_RX_LOCK(rxq); } - np->rx.rsp_cons = i; + rxq->ring.rsp_cons = i; #if (defined(INET) || defined(INET6)) /* * Flush any outstanding LRO work */ while (!SLIST_EMPTY(&lro->lro_active)) { queued = SLIST_FIRST(&lro->lro_active); SLIST_REMOVE_HEAD(&lro->lro_active, next); tcp_lro_flush(lro, queued); } #endif -#if 0 - /* If we get a callback with very few responses, reduce fill target. */ - /* NB. Note exponential increase, linear decrease. */ - if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > - ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) - np->rx_target = np->rx_min_target; -#endif + xn_alloc_rx_buffers(rxq); - network_alloc_rx_buffers(np); - - RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, work_to_do); + RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do); } while (work_to_do); } static void -xn_txeof(struct netfront_info *np) +xn_txeof(struct netfront_txq *txq) { RING_IDX i, prod; unsigned short id; struct ifnet *ifp; netif_tx_response_t *txr; struct mbuf *m; + struct netfront_info *np = txq->info; - XN_TX_LOCK_ASSERT(np); + XN_TX_LOCK_ASSERT(txq); if (!netfront_carrier_ok(np)) return; ifp = np->xn_ifp; do { - prod = np->tx.sring->rsp_prod; + prod = txq->ring.sring->rsp_prod; rmb(); /* Ensure we see responses up to 'rp'. */ - for (i = np->tx.rsp_cons; i != prod; i++) { - txr = RING_GET_RESPONSE(&np->tx, i); + for (i = txq->ring.rsp_cons; i != prod; i++) { + txr = RING_GET_RESPONSE(&txq->ring, i); if (txr->status == NETIF_RSP_NULL) continue; if (txr->status != NETIF_RSP_OKAY) { printf("%s: WARNING: response is %d!\n", __func__, txr->status); } id = txr->id; - m = np->tx_mbufs[id]; - KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); + m = txq->mbufs[id]; + KASSERT(m != NULL, ("mbuf not found in chain")); KASSERT((uintptr_t)m > NET_TX_RING_SIZE, ("mbuf already on the free list, but we're " "trying to free it again!")); M_ASSERTVALID(m); /* * Increment packet count if this is the last * mbuf of the chain. */ if (!m->m_next) if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if (__predict_false(gnttab_query_foreign_access( - np->grant_tx_ref[id]) != 0)) { + txq->grant_ref[id]) != 0)) { panic("%s: grant id %u still in use by the " "backend", __func__, id); } - gnttab_end_foreign_access_ref( - np->grant_tx_ref[id]); + gnttab_end_foreign_access_ref(txq->grant_ref[id]); gnttab_release_grant_reference( - &np->gref_tx_head, np->grant_tx_ref[id]); - np->grant_tx_ref[id] = GRANT_REF_INVALID; + &txq->gref_head, txq->grant_ref[id]); + txq->grant_ref[id] = GRANT_REF_INVALID; - np->tx_mbufs[id] = NULL; - add_id_to_freelist(np->tx_mbufs, id); - np->xn_cdata.xn_tx_chain_cnt--; + txq->mbufs[id] = NULL; + add_id_to_freelist(txq->mbufs, id); + txq->mbufs_cnt--; m_free(m); - /* Only mark the queue active if we've freed up at least one slot to try */ + /* Only mark the txq active if we've freed up at least one slot to try */ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } - np->tx.rsp_cons = prod; + txq->ring.rsp_cons = prod; /* * Set a new event, then check for race with update of * tx_cons. Note that it is essential to schedule a * callback, no matter how few buffers are pending. Even if * there is space in the transmit ring, higher layers may * be blocked because too much data is outstanding: in such * cases notification from Xen is likely to be the only kick * that we'll get. */ - np->tx.sring->rsp_event = - prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; + txq->ring.sring->rsp_event = + prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1; mb(); - } while (prod != np->tx.sring->rsp_prod); + } while (prod != txq->ring.sring->rsp_prod); - if (np->tx_full && - ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { - np->tx_full = 0; -#if 0 - if (np->user_state == UST_OPEN) - netif_wake_queue(dev); -#endif + if (txq->full && + ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) { + txq->full = false; + taskqueue_enqueue(txq->tq, &txq->intrtask); } } + static void -xn_intr(void *xsc) +xn_rxq_intr(void *xrxq) { - struct netfront_info *np = xsc; - struct ifnet *ifp = np->xn_ifp; + struct netfront_rxq *rxq = xrxq; -#if 0 - if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod && - likely(netfront_carrier_ok(np)) && - ifp->if_drv_flags & IFF_DRV_RUNNING)) - return; -#endif - if (RING_HAS_UNCONSUMED_RESPONSES(&np->tx)) { - XN_TX_LOCK(np); - xn_txeof(np); - XN_TX_UNLOCK(np); - } + taskqueue_enqueue_fast(rxq->tq, &rxq->intrtask); +} - XN_RX_LOCK(np); - xn_rxeof(np); - XN_RX_UNLOCK(np); +static void +xn_txq_intr(void *xtxq) +{ + struct netfront_txq *txq = xtxq; - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - xn_start(ifp); + taskqueue_enqueue_fast(txq->tq, &txq->intrtask); } +static int +xn_intr(void *xsc) +{ + struct netfront_txq *txq = xsc; + struct netfront_info *np = txq->info; + struct netfront_rxq *rxq = &np->rxq[txq->id]; + + /* kick both tx and rx */ + xn_rxq_intr(rxq); + xn_txq_intr(txq); + + return (FILTER_HANDLED); +} + static void -xennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, - grant_ref_t ref) +xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m, + grant_ref_t ref) { - int new = xennet_rxidx(np->rx.req_prod_pvt); + int new = xn_rxidx(rxq->ring.req_prod_pvt); - KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL")); - np->rx_mbufs[new] = m; - np->grant_rx_ref[new] = ref; - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; - np->rx.req_prod_pvt++; + KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL")); + rxq->mbufs[new] = m; + rxq->grant_ref[new] = ref; + RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new; + RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref; + rxq->ring.req_prod_pvt++; } static int -xennet_get_extras(struct netfront_info *np, +xn_get_extras(struct netfront_rxq *rxq, struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) { struct netif_extra_info *extra; int err = 0; do { struct mbuf *m; grant_ref_t ref; if (__predict_false(*cons + 1 == rp)) { -#if 0 - if (net_ratelimit()) - WPRINTK("Missing extra info\n"); -#endif err = EINVAL; break; } extra = (struct netif_extra_info *) - RING_GET_RESPONSE(&np->rx, ++(*cons)); + RING_GET_RESPONSE(&rxq->ring, ++(*cons)); if (__predict_false(!extra->type || extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { -#if 0 - if (net_ratelimit()) - WPRINTK("Invalid extra type: %d\n", - extra->type); -#endif err = EINVAL; } else { memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); } - m = xennet_get_rx_mbuf(np, *cons); - ref = xennet_get_rx_ref(np, *cons); - xennet_move_rx_slot(np, m, ref); + m = xn_get_rx_mbuf(rxq, *cons); + ref = xn_get_rx_ref(rxq, *cons); + xn_move_rx_slot(rxq, m, ref); } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); return err; } static int -xennet_get_responses(struct netfront_info *np, - struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, - struct mbuf **list) +xn_get_responses(struct netfront_rxq *rxq, + struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, + struct mbuf **list) { struct netif_rx_response *rx = &rinfo->rx; struct netif_extra_info *extras = rinfo->extras; struct mbuf *m, *m0, *m_prev; - grant_ref_t ref = xennet_get_rx_ref(np, *cons); + grant_ref_t ref = xn_get_rx_ref(rxq, *cons); RING_IDX ref_cons = *cons; int frags = 1; int err = 0; u_long ret; - m0 = m = m_prev = xennet_get_rx_mbuf(np, *cons); + m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons); if (rx->flags & NETRXF_extra_info) { - err = xennet_get_extras(np, extras, rp, cons); + err = xn_get_extras(rxq, extras, rp, cons); } if (m0 != NULL) { m0->m_pkthdr.len = 0; m0->m_next = NULL; } for (;;) { #if 0 DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", rx->status, rx->offset, frags); #endif if (__predict_false(rx->status < 0 || rx->offset + rx->status > PAGE_SIZE)) { -#if 0 - if (net_ratelimit()) - WPRINTK("rx->offset: %x, size: %u\n", - rx->offset, rx->status); -#endif - xennet_move_rx_slot(np, m, ref); + xn_move_rx_slot(rxq, m, ref); if (m0 == m) m0 = NULL; m = NULL; err = EINVAL; goto next_skip_queue; } /* * This definitely indicates a bug, either in this driver or in * the backend driver. In future this should flag the bad * situation to the system controller to reboot the backed. */ if (ref == GRANT_REF_INVALID) { - -#if 0 - if (net_ratelimit()) - WPRINTK("Bad rx response id %d.\n", rx->id); -#endif - printf("%s: Bad rx response id %d.\n", __func__,rx->id); + printf("%s: Bad rx response id %d.\n", __func__, rx->id); err = EINVAL; goto next; } ret = gnttab_end_foreign_access_ref(ref); KASSERT(ret, ("Unable to end access to grant references")); - gnttab_release_grant_reference(&np->gref_rx_head, ref); + gnttab_release_grant_reference(&rxq->gref_head, ref); next: if (m == NULL) break; m->m_len = rx->status; m->m_data += rx->offset; m0->m_pkthdr.len += rx->status; next_skip_queue: if (!(rx->flags & NETRXF_more_data)) break; if (*cons + frags == rp) { if (net_ratelimit()) WPRINTK("Need more frags\n"); err = ENOENT; printf("%s: cons %u frags %u rp %u, not enough frags\n", __func__, *cons, frags, rp); break; } /* * Note that m can be NULL, if rx->status < 0 or if * rx->offset + rx->status > PAGE_SIZE above. */ m_prev = m; - rx = RING_GET_RESPONSE(&np->rx, *cons + frags); - m = xennet_get_rx_mbuf(np, *cons + frags); + rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags); + m = xn_get_rx_mbuf(rxq, *cons + frags); /* * m_prev == NULL can happen if rx->status < 0 or if * rx->offset + * rx->status > PAGE_SIZE above. */ if (m_prev != NULL) m_prev->m_next = m; /* * m0 can be NULL if rx->status < 0 or if * rx->offset + * rx->status > PAGE_SIZE above. */ if (m0 == NULL) m0 = m; m->m_next = NULL; - ref = xennet_get_rx_ref(np, *cons + frags); + ref = xn_get_rx_ref(rxq, *cons + frags); ref_cons = *cons + frags; frags++; } *list = m0; *cons += frags; return (err); } -static void -xn_tick_locked(struct netfront_info *sc) -{ - XN_RX_LOCK_ASSERT(sc); - callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); - - /* XXX placeholder for printing debug information */ -} - -static void -xn_tick(void *xsc) -{ - struct netfront_info *sc; - - sc = xsc; - XN_RX_LOCK(sc); - xn_tick_locked(sc); - XN_RX_UNLOCK(sc); -} - /** * \brief Count the number of fragments in an mbuf chain. * * Surprisingly, there isn't an M* macro for this. */ static inline int xn_count_frags(struct mbuf *m) { int nfrags; for (nfrags = 0; m != NULL; m = m->m_next) nfrags++; return (nfrags); } /** * Given an mbuf chain, make sure we have enough room and then push * it onto the transmit ring. */ static int -xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head) +xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head) { - struct ifnet *ifp; struct mbuf *m; + struct netfront_info *np = txq->info; + struct ifnet *ifp = np->xn_ifp; u_int nfrags; int otherend_id; - ifp = sc->xn_ifp; - /** * Defragment the mbuf if necessary. */ nfrags = xn_count_frags(m_head); /* * Check to see whether this request is longer than netback * can handle, and try to defrag it. */ /** * It is a bit lame, but the netback driver in Linux can't * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of * the Linux network stack. */ - if (nfrags > sc->maxfrags) { + if (nfrags > np->maxfrags) { m = m_defrag(m_head, M_NOWAIT); if (!m) { /* * Defrag failed, so free the mbuf and * therefore drop the packet. */ m_freem(m_head); return (EMSGSIZE); } m_head = m; } /* Determine how many fragments now exist */ nfrags = xn_count_frags(m_head); /* * Check to see whether the defragmented packet has too many * segments for the Linux netback driver. */ /** * The FreeBSD TCP stack, with TSO enabled, can produce a chain * of mbufs longer than Linux can handle. Make sure we don't * pass a too-long chain over to the other side by dropping the * packet. It doesn't look like there is currently a way to * tell the TCP stack to generate a shorter chain of packets. */ if (nfrags > MAX_TX_REQ_FRAGS) { #ifdef DEBUG printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " "won't be able to handle it, dropping\n", __func__, nfrags, MAX_TX_REQ_FRAGS); #endif m_freem(m_head); return (EMSGSIZE); } /* * This check should be redundant. We've already verified that we * have enough slots in the ring to handle a packet of maximum * size, and that our packet is less than the maximum size. Keep * it in here as an assert for now just to make certain that - * xn_tx_chain_cnt is accurate. + * chain_cnt is accurate. */ - KASSERT((sc->xn_cdata.xn_tx_chain_cnt + nfrags) <= NET_TX_RING_SIZE, - ("%s: xn_tx_chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " - "(%d)!", __func__, (int) sc->xn_cdata.xn_tx_chain_cnt, + KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE, + ("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " + "(%d)!", __func__, (int) txq->mbufs_cnt, (int) nfrags, (int) NET_TX_RING_SIZE)); /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ m = m_head; - otherend_id = xenbus_get_otherend_id(sc->xbdev); + otherend_id = xenbus_get_otherend_id(np->xbdev); for (m = m_head; m; m = m->m_next) { netif_tx_request_t *tx; uintptr_t id; grant_ref_t ref; u_long mfn; /* XXX Wrong type? */ - tx = RING_GET_REQUEST(&sc->tx, sc->tx.req_prod_pvt); - id = get_id_from_freelist(sc->tx_mbufs); + tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt); + id = get_id_from_freelist(txq->mbufs); if (id == 0) panic("%s: was allocated the freelist head!\n", __func__); - sc->xn_cdata.xn_tx_chain_cnt++; - if (sc->xn_cdata.xn_tx_chain_cnt > NET_TX_RING_SIZE) + txq->mbufs_cnt++; + if (txq->mbufs_cnt > NET_TX_RING_SIZE) panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", __func__); - sc->tx_mbufs[id] = m; + txq->mbufs[id] = m; tx->id = id; - ref = gnttab_claim_grant_reference(&sc->gref_tx_head); + ref = gnttab_claim_grant_reference(&txq->gref_head); KASSERT((short)ref >= 0, ("Negative ref")); mfn = virt_to_mfn(mtod(m, vm_offset_t)); gnttab_grant_foreign_access_ref(ref, otherend_id, mfn, GNTMAP_readonly); - tx->gref = sc->grant_tx_ref[id] = ref; + tx->gref = txq->grant_ref[id] = ref; tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); tx->flags = 0; if (m == m_head) { /* * The first fragment has the entire packet * size, subsequent fragments have just the * fragment size. The backend works out the * true size of the first fragment by * subtracting the sizes of the other * fragments. */ tx->size = m->m_pkthdr.len; /* * The first fragment contains the checksum flags * and is optionally followed by extra data for * TSO etc. */ /** * CSUM_TSO requires checksum offloading. * Some versions of FreeBSD fail to * set CSUM_TCP in the CSUM_TSO case, * so we have to test for CSUM_TSO * explicitly. */ if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_TSO)) { tx->flags |= (NETTXF_csum_blank | NETTXF_data_validated); } if (m->m_pkthdr.csum_flags & CSUM_TSO) { struct netif_extra_info *gso = (struct netif_extra_info *) - RING_GET_REQUEST(&sc->tx, - ++sc->tx.req_prod_pvt); + RING_GET_REQUEST(&txq->ring, + ++txq->ring.req_prod_pvt); tx->flags |= NETTXF_extra_info; gso->u.gso.size = m->m_pkthdr.tso_segsz; gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; gso->u.gso.pad = 0; gso->u.gso.features = 0; gso->type = XEN_NETIF_EXTRA_TYPE_GSO; gso->flags = 0; } } else { tx->size = m->m_len; } if (m->m_next) tx->flags |= NETTXF_more_data; - sc->tx.req_prod_pvt++; + txq->ring.req_prod_pvt++; } BPF_MTAP(ifp, m_head); - sc->stats.tx_bytes += m_head->m_pkthdr.len; - sc->stats.tx_packets++; + xn_txeof(txq); + txq->stats.tx_bytes += m_head->m_pkthdr.len; + txq->stats.tx_packets++; + return (0); } -static void -xn_start_locked(struct ifnet *ifp) -{ - struct netfront_info *sc; - struct mbuf *m_head; - int notify; - - sc = ifp->if_softc; - - if (!netfront_carrier_ok(sc)) - return; - - /* - * While we have enough transmit slots available for at least one - * maximum-sized packet, pull mbufs off the queue and put them on - * the transmit ring. - */ - while (xn_tx_slot_available(sc)) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - if (xn_assemble_tx_request(sc, m_head) != 0) - break; - } - - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); - if (notify) - xen_intr_signal(sc->xen_intr_handle); - - if (RING_FULL(&sc->tx)) { - sc->tx_full = 1; -#if 0 - netif_stop_queue(dev); -#endif - } -} - -static void -xn_start(struct ifnet *ifp) -{ - struct netfront_info *sc; - sc = ifp->if_softc; - XN_TX_LOCK(sc); - xn_start_locked(ifp); - XN_TX_UNLOCK(sc); -} - /* equivalent of network_open() in Linux */ static void -xn_ifinit_locked(struct netfront_info *sc) +xn_ifinit_locked(struct netfront_info *np) { struct ifnet *ifp; + int i; + struct netfront_rxq *rxq; - XN_LOCK_ASSERT(sc); + XN_LOCK_ASSERT(np); - ifp = sc->xn_ifp; + ifp = np->xn_ifp; if (ifp->if_drv_flags & IFF_DRV_RUNNING) return; - xn_stop(sc); + xn_stop(np); - network_alloc_rx_buffers(sc); - sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; + for (i = 0; i < np->num_queues; i++) { + rxq = &np->rxq[i]; + xn_alloc_rx_buffers(rxq); + rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1; + } ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if_link_state_change(ifp, LINK_STATE_UP); - - callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); } static void xn_ifinit(void *xsc) { struct netfront_info *sc = xsc; XN_LOCK(sc); xn_ifinit_locked(sc); XN_UNLOCK(sc); } static int xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct netfront_info *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; #ifdef INET struct ifaddr *ifa = (struct ifaddr *)data; #endif int mask, error = 0; switch(cmd) { case SIOCSIFADDR: #ifdef INET XN_LOCK(sc); if (ifa->ifa_addr->sa_family == AF_INET) { ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) xn_ifinit_locked(sc); arp_ifinit(ifp, ifa); XN_UNLOCK(sc); } else { XN_UNLOCK(sc); #endif error = ether_ioctl(ifp, cmd, data); #ifdef INET } #endif break; case SIOCSIFMTU: - /* XXX can we alter the MTU on a VN ?*/ -#ifdef notyet - if (ifr->ifr_mtu > XN_JUMBO_MTU) - error = EINVAL; - else -#endif - { - ifp->if_mtu = ifr->ifr_mtu; - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - xn_ifinit(sc); - } + ifp->if_mtu = ifr->ifr_mtu; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + xn_ifinit(sc); break; case SIOCSIFFLAGS: XN_LOCK(sc); if (ifp->if_flags & IFF_UP) { /* * If only the state of the PROMISC flag changed, * then just use the 'set promisc mode' command * instead of reinitializing the entire NIC. Doing * a full re-init means reloading the firmware and * waiting for it to start up, which may take a * second or two. */ -#ifdef notyet - /* No promiscuous mode with Xen */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->xn_if_flags & IFF_PROMISC)) { - XN_SETBIT(sc, XN_RX_MODE, - XN_RXMODE_RX_PROMISC); - } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->xn_if_flags & IFF_PROMISC) { - XN_CLRBIT(sc, XN_RX_MODE, - XN_RXMODE_RX_PROMISC); - } else -#endif - xn_ifinit_locked(sc); + xn_ifinit_locked(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { xn_stop(sc); } } sc->xn_if_flags = ifp->if_flags; XN_UNLOCK(sc); error = 0; break; case SIOCSIFCAP: mask = ifr->ifr_reqcap ^ ifp->if_capenable; if (mask & IFCAP_TXCSUM) { if (IFCAP_TXCSUM & ifp->if_capenable) { ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); } else { ifp->if_capenable |= IFCAP_TXCSUM; ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); } } if (mask & IFCAP_RXCSUM) { ifp->if_capenable ^= IFCAP_RXCSUM; } if (mask & IFCAP_TSO4) { if (IFCAP_TSO4 & ifp->if_capenable) { ifp->if_capenable &= ~IFCAP_TSO4; ifp->if_hwassist &= ~CSUM_TSO; } else if (IFCAP_TXCSUM & ifp->if_capenable) { ifp->if_capenable |= IFCAP_TSO4; ifp->if_hwassist |= CSUM_TSO; } else { IPRINTK("Xen requires tx checksum offload" " be enabled to use TSO\n"); error = EINVAL; } } if (mask & IFCAP_LRO) { ifp->if_capenable ^= IFCAP_LRO; } error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: -#ifdef notyet - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - XN_LOCK(sc); - xn_setmulti(sc); - XN_UNLOCK(sc); - error = 0; - } -#endif break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); break; default: error = ether_ioctl(ifp, cmd, data); } return (error); } static void xn_stop(struct netfront_info *sc) { struct ifnet *ifp; XN_LOCK_ASSERT(sc); ifp = sc->xn_ifp; - callout_stop(&sc->xn_stat_ch); - - xn_free_rx_ring(sc); - xn_free_tx_ring(sc); - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); if_link_state_change(ifp, LINK_STATE_DOWN); } -/* START of Xenolinux helper functions adapted to FreeBSD */ -int -network_connect(struct netfront_info *np) +static void +xn_rebuild_rx_bufs(struct netfront_rxq *rxq) { - int i, requeue_idx, error; + int requeue_idx, i; grant_ref_t ref; netif_rx_request_t *req; + + for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { + struct mbuf *m; + u_long pfn; + + if (rxq->mbufs[i] == NULL) + continue; + + m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i); + ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i); + + req = RING_GET_REQUEST(&rxq->ring, requeue_idx); + pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; + + gnttab_grant_foreign_access_ref(ref, + xenbus_get_otherend_id(rxq->info->xbdev), + pfn, 0); + + req->gref = ref; + req->id = requeue_idx; + + requeue_idx++; + } + + rxq->ring.req_prod_pvt = requeue_idx; +} + +/* START of Xenolinux helper functions adapted to FreeBSD */ +int +xn_connect(struct netfront_info *np) +{ + int i, error; u_int feature_rx_copy; + struct netfront_rxq *rxq; + struct netfront_txq *txq; error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), "feature-rx-copy", NULL, "%u", &feature_rx_copy); - if (error) + if (error != 0) feature_rx_copy = 0; /* We only support rx copy. */ if (!feature_rx_copy) return (EPROTONOSUPPORT); /* Recovery procedure: */ error = talk_to_backend(np->xbdev, np); - if (error) + if (error != 0) return (error); /* Step 1: Reinitialise variables. */ xn_query_features(np); xn_configure_features(np); - netif_release_tx_bufs(np); - /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ - for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { - struct mbuf *m; - u_long pfn; + /* Step 2: Release TX buffer */ + for (i = 0; i < np->num_queues; i++) { + txq = &np->txq[i]; + xn_release_tx_bufs(txq); + } - if (np->rx_mbufs[i] == NULL) - continue; - - m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i); - ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); - - req = RING_GET_REQUEST(&np->rx, requeue_idx); - pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; - - gnttab_grant_foreign_access_ref(ref, - xenbus_get_otherend_id(np->xbdev), - pfn, 0); - - req->gref = ref; - req->id = requeue_idx; - - requeue_idx++; + /* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */ + for (i = 0; i < np->num_queues; i++) { + rxq = &np->rxq[i]; + xn_rebuild_rx_bufs(rxq); } - np->rx.req_prod_pvt = requeue_idx; - - /* Step 3: All public and private state should now be sane. Get + /* Step 4: All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver * domain a kick because we've probably just requeued some * packets. */ netfront_carrier_on(np); - xen_intr_signal(np->xen_intr_handle); - XN_TX_LOCK(np); - xn_txeof(np); - XN_TX_UNLOCK(np); - network_alloc_rx_buffers(np); + for (i = 0; i < np->num_queues; i++) { + txq = &np->txq[i]; + xen_intr_signal(txq->xen_intr_handle); + XN_TX_LOCK(txq); + xn_txeof(txq); + XN_TX_UNLOCK(txq); + xn_alloc_rx_buffers(rxq); + } return (0); } static void xn_query_features(struct netfront_info *np) { int val; device_printf(np->xbdev, "backend features:"); if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), "feature-sg", NULL, "%d", &val) < 0) val = 0; np->maxfrags = 1; if (val) { np->maxfrags = MAX_TX_REQ_FRAGS; printf(" feature-sg"); } if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), "feature-gso-tcpv4", NULL, "%d", &val) < 0) val = 0; np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); if (val) { np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; printf(" feature-gso-tcp4"); } printf("\n"); } static int xn_configure_features(struct netfront_info *np) { int err, cap_enabled; +#if (defined(INET) || defined(INET6)) + int i; +#endif err = 0; if (np->xn_resume && ((np->xn_ifp->if_capenable & np->xn_ifp->if_capabilities) == np->xn_ifp->if_capenable)) { /* Current options are available, no need to do anything. */ return (0); } /* Try to preserve as many options as possible. */ if (np->xn_resume) cap_enabled = np->xn_ifp->if_capenable; else cap_enabled = UINT_MAX; #if (defined(INET) || defined(INET6)) - if ((np->xn_ifp->if_capenable & IFCAP_LRO) == (cap_enabled & IFCAP_LRO)) - tcp_lro_free(&np->xn_lro); + for (i = 0; i < np->num_queues; i++) + if ((np->xn_ifp->if_capenable & IFCAP_LRO) == + (cap_enabled & IFCAP_LRO)) + tcp_lro_free(&np->rxq[i].lro); #endif np->xn_ifp->if_capenable = np->xn_ifp->if_capabilities & ~(IFCAP_LRO|IFCAP_TSO4) & cap_enabled; np->xn_ifp->if_hwassist &= ~CSUM_TSO; #if (defined(INET) || defined(INET6)) - if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) == - (cap_enabled & IFCAP_LRO)) { - err = tcp_lro_init(&np->xn_lro); - if (err) { - device_printf(np->xbdev, "LRO initialization failed\n"); - } else { - np->xn_lro.ifp = np->xn_ifp; - np->xn_ifp->if_capenable |= IFCAP_LRO; + for (i = 0; i < np->num_queues; i++) { + if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) == + (cap_enabled & IFCAP_LRO)) { + err = tcp_lro_init(&np->rxq[i].lro); + if (err != 0) { + device_printf(np->xbdev, "LRO initialization failed\n"); + } else { + np->rxq[i].lro.ifp = np->xn_ifp; + np->xn_ifp->if_capenable |= IFCAP_LRO; + } } } if ((np->xn_ifp->if_capabilities & IFCAP_TSO4) == (cap_enabled & IFCAP_TSO4)) { np->xn_ifp->if_capenable |= IFCAP_TSO4; np->xn_ifp->if_hwassist |= CSUM_TSO; } #endif return (err); } +static int +xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m) +{ + struct netfront_info *np; + struct ifnet *ifp; + struct buf_ring *br; + int error, notify; + + np = txq->info; + br = txq->br; + ifp = np->xn_ifp; + error = 0; + + XN_TX_LOCK_ASSERT(txq); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + !netfront_carrier_ok(np)) { + if (m != NULL) + error = drbr_enqueue(ifp, br, m); + return (error); + } + + if (m != NULL) { + error = drbr_enqueue(ifp, br, m); + if (error != 0) + return (error); + } + + while ((m = drbr_peek(ifp, br)) != NULL) { + if (!xn_tx_slot_available(txq)) { + drbr_putback(ifp, br, m); + break; + } + + error = xn_assemble_tx_request(txq, m); + /* xn_assemble_tx_request always consumes the mbuf*/ + if (error != 0) { + drbr_advance(ifp, br); + break; + } + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify); + if (notify) + xen_intr_signal(txq->xen_intr_handle); + + drbr_advance(ifp, br); + } + + if (RING_FULL(&txq->ring)) + txq->full = true; + + return (0); +} + +static int +xn_txq_mq_start(struct ifnet *ifp, struct mbuf *m) +{ + struct netfront_info *np; + struct netfront_txq *txq; + int i, npairs, error; + + np = ifp->if_softc; + npairs = np->num_queues; + + /* check if flowid is set */ + if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) + i = m->m_pkthdr.flowid % npairs; + else + i = curcpu % npairs; + + txq = &np->txq[i]; + + if (XN_TX_TRYLOCK(txq) != 0) { + error = xn_txq_mq_start_locked(txq, m); + XN_TX_UNLOCK(txq); + } else { + error = drbr_enqueue(ifp, txq->br, m); + taskqueue_enqueue(txq->tq, &txq->defrtask); + } + + return (error); +} + +static void +xn_qflush(struct ifnet *ifp) +{ + struct netfront_info *np; + struct netfront_txq *txq; + struct mbuf *m; + int i; + + np = ifp->if_softc; + + for (i = 0; i < np->num_queues; i++) { + txq = &np->txq[i]; + + XN_TX_LOCK(txq); + while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) + m_freem(m); + XN_TX_UNLOCK(txq); + } + + if_qflush(ifp); +} + /** * Create a network device. * @param dev Newbus device representing this virtual NIC. */ int create_netdev(device_t dev) { - int i; struct netfront_info *np; int err; struct ifnet *ifp; np = device_get_softc(dev); np->xbdev = dev; - mtx_init(&np->tx_lock, "xntx", "netfront transmit lock", MTX_DEF); - mtx_init(&np->rx_lock, "xnrx", "netfront receive lock", MTX_DEF); mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); - np->rx_target = RX_MIN_TARGET; np->rx_min_target = RX_MIN_TARGET; np->rx_max_target = RX_MAX_TARGET; - /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ - for (i = 0; i <= NET_TX_RING_SIZE; i++) { - np->tx_mbufs[i] = (void *) ((u_long) i+1); - np->grant_tx_ref[i] = GRANT_REF_INVALID; - } - np->tx_mbufs[NET_TX_RING_SIZE] = (void *)0; - - for (i = 0; i <= NET_RX_RING_SIZE; i++) { - - np->rx_mbufs[i] = NULL; - np->grant_rx_ref[i] = GRANT_REF_INVALID; - } - - mbufq_init(&np->xn_rx_batch, INT_MAX); - - /* A grant for every tx ring slot */ - if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, - &np->gref_tx_head) != 0) { - IPRINTK("#### netfront can't alloc tx grant refs\n"); - err = ENOMEM; - goto error; - } - /* A grant for every rx ring slot */ - if (gnttab_alloc_grant_references(RX_MAX_TARGET, - &np->gref_rx_head) != 0) { - WPRINTK("#### netfront can't alloc rx grant refs\n"); - gnttab_free_grant_references(np->gref_tx_head); - err = ENOMEM; - goto error; - } - err = xen_net_read_mac(dev, np->mac); - if (err) { - gnttab_free_grant_references(np->gref_rx_head); - gnttab_free_grant_references(np->gref_tx_head); + if (err != 0) goto error; - } /* Set up ifnet structure */ ifp = np->xn_ifp = if_alloc(IFT_ETHER); ifp->if_softc = np; if_initname(ifp, "xn", device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = xn_ioctl; - ifp->if_start = xn_start; -#ifdef notyet - ifp->if_watchdog = xn_watchdog; -#endif + + ifp->if_transmit = xn_txq_mq_start; + ifp->if_qflush = xn_qflush; + ifp->if_init = xn_ifinit; - ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; ifp->if_hwassist = XN_CSUM_FEATURES; ifp->if_capabilities = IFCAP_HWCSUM; ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); ifp->if_hw_tsomaxsegcount = MAX_TX_REQ_FRAGS; ifp->if_hw_tsomaxsegsize = PAGE_SIZE; ether_ifattach(ifp, np->mac); - callout_init(&np->xn_stat_ch, 1); netfront_carrier_off(np); return (0); error: KASSERT(err != 0, ("Error path with no error code specified")); return (err); } -/** - * Handle the change of state of the backend to Closing. We must delete our - * device-layer structures now, to ensure that writes are flushed through to - * the backend. Once is this done, we can switch to Closed in - * acknowledgement. - */ -#if 0 -static void -netfront_closing(device_t dev) -{ -#if 0 - struct netfront_info *info = dev->dev_driver_data; - - DPRINTK("netfront_closing: %s removed\n", dev->nodename); - - close_netdev(info); -#endif - xenbus_switch_state(dev, XenbusStateClosed); -} -#endif - static int netfront_detach(device_t dev) { struct netfront_info *info = device_get_softc(dev); DPRINTK("%s\n", xenbus_get_node(dev)); netif_free(info); return 0; } static void -netif_free(struct netfront_info *info) +netif_free(struct netfront_info *np) { - XN_LOCK(info); - xn_stop(info); - XN_UNLOCK(info); - callout_drain(&info->xn_stat_ch); - netif_disconnect_backend(info); - if (info->xn_ifp != NULL) { - ether_ifdetach(info->xn_ifp); - if_free(info->xn_ifp); - info->xn_ifp = NULL; + + XN_LOCK(np); + xn_stop(np); + XN_UNLOCK(np); + netif_disconnect_backend(np); + free(np->rxq, M_DEVBUF); + free(np->txq, M_DEVBUF); + if (np->xn_ifp != NULL) { + ether_ifdetach(np->xn_ifp); + if_free(np->xn_ifp); + np->xn_ifp = NULL; } - ifmedia_removeall(&info->sc_media); + ifmedia_removeall(&np->sc_media); } static void -netif_disconnect_backend(struct netfront_info *info) +netif_disconnect_backend(struct netfront_info *np) { - XN_RX_LOCK(info); - XN_TX_LOCK(info); - netfront_carrier_off(info); - XN_TX_UNLOCK(info); - XN_RX_UNLOCK(info); + u_int i; - free_ring(&info->tx_ring_ref, &info->tx.sring); - free_ring(&info->rx_ring_ref, &info->rx.sring); + for (i = 0; i < np->num_queues; i++) { + XN_RX_LOCK(&np->rxq[i]); + XN_TX_LOCK(&np->txq[i]); + } + netfront_carrier_off(np); + for (i = 0; i < np->num_queues; i++) { + XN_RX_UNLOCK(&np->rxq[i]); + XN_TX_UNLOCK(&np->txq[i]); + } - xen_intr_unbind(&info->xen_intr_handle); -} - -static void -free_ring(int *ref, void *ring_ptr_ref) -{ - void **ring_ptr_ptr = ring_ptr_ref; - - if (*ref != GRANT_REF_INVALID) { - /* This API frees the associated storage. */ - gnttab_end_foreign_access(*ref, *ring_ptr_ptr); - *ref = GRANT_REF_INVALID; + for (i = 0; i < np->num_queues; i++) { + disconnect_rxq(&np->rxq[i]); + disconnect_txq(&np->txq[i]); } - *ring_ptr_ptr = NULL; } static int xn_ifmedia_upd(struct ifnet *ifp) { + return (0); } static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { + ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; } /* ** Driver registration ** */ static device_method_t netfront_methods[] = { /* Device interface */ DEVMETHOD(device_probe, netfront_probe), DEVMETHOD(device_attach, netfront_attach), DEVMETHOD(device_detach, netfront_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, netfront_suspend), DEVMETHOD(device_resume, netfront_resume), /* Xenbus interface */ DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), DEVMETHOD_END }; static driver_t netfront_driver = { "xn", netfront_methods, sizeof(struct netfront_info), }; devclass_t netfront_devclass; DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, NULL); Index: projects/release-pkg/sys/modules/ix/Makefile =================================================================== --- projects/release-pkg/sys/modules/ix/Makefile (revision 294447) +++ projects/release-pkg/sys/modules/ix/Makefile (revision 294448) @@ -1,15 +1,15 @@ #$FreeBSD$ .PATH: ${.CURDIR}/../../dev/ixgbe KMOD = if_ix -SRCS = device_if.h bus_if.h pci_if.h +SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h SRCS += opt_inet.h opt_inet6.h opt_rss.h SRCS += if_ix.c ix_txrx.c ixgbe_osdep.c # Shared source SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c ixgbe_x550.c CFLAGS+= -I${.CURDIR}/../../dev/ixgbe -DSMP .include Index: projects/release-pkg/sys/modules/ixlv/Makefile =================================================================== --- projects/release-pkg/sys/modules/ixlv/Makefile (revision 294447) +++ projects/release-pkg/sys/modules/ixlv/Makefile (revision 294448) @@ -1,20 +1,20 @@ #$FreeBSD$ .PATH: ${.CURDIR}/../../dev/ixl KMOD = if_ixlv -SRCS = device_if.h bus_if.h pci_if.h opt_bdg.h +SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h opt_bdg.h SRCS += opt_inet.h opt_inet6.h opt_rss.h SRCS += if_ixlv.c ixlvc.c ixl_txrx.c i40e_osdep.c # Shared source SRCS += i40e_common.c i40e_nvm.c i40e_adminq.c CFLAGS += -DSMP # Add Flow Director support # CFLAGS += -DIXL_FDIR # Debug messages / sysctls # CFLAGS += -DIXLE_DEBUG .include Index: projects/release-pkg/sys/modules/ixv/Makefile =================================================================== --- projects/release-pkg/sys/modules/ixv/Makefile (revision 294447) +++ projects/release-pkg/sys/modules/ixv/Makefile (revision 294448) @@ -1,15 +1,15 @@ #$FreeBSD$ .PATH: ${.CURDIR}/../../dev/ixgbe KMOD = if_ixv -SRCS = device_if.h bus_if.h pci_if.h +SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h SRCS += opt_inet.h opt_inet6.h opt_rss.h SRCS += if_ixv.c ix_txrx.c ixgbe_osdep.c # Shared source SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c ixgbe_x550.c CFLAGS+= -I${.CURDIR}/../../dev/ixgbe -DSMP .include Index: projects/release-pkg/sys/netinet6/ip6_forward.c =================================================================== --- projects/release-pkg/sys/netinet6/ip6_forward.c (revision 294447) +++ projects/release-pkg/sys/netinet6/ip6_forward.c (revision 294448) @@ -1,627 +1,630 @@ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipfw.h" #include "opt_ipsec.h" #include "opt_ipstealth.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IPSEC #include #include #include #include #endif /* IPSEC */ /* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful * icmp message because icmp doesn't have a large enough repertoire * of codes and types. * * If not forwarding, just drop the packet. This could be confusing * if ipforwarding was zero but some routing protocol was advancing * us as a gateway to somewhere. However, we must let the routing * protocol deal with that. * */ void ip6_forward(struct mbuf *m, int srcrt) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct sockaddr_in6 *dst = NULL; struct rtentry *rt = NULL; struct route_in6 rin6; int error, type = 0, code = 0; struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ u_int32_t inzone, outzone; struct in6_addr src_in6, dst_in6, odst; #ifdef IPSEC struct secpolicy *sp = NULL; #endif #ifdef SCTP int sw_csum; #endif struct m_tag *fwd_tag; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; /* * Do not forward packets to multicast destination (should be handled * by ip6_mforward(). * Do not forward packets with unspecified source. It was discussed * in July 2000, on the ipngwg mailing list. */ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { IP6STAT_INC(ip6s_cantforward); /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (V_ip6_log_time + V_ip6_log_interval < time_uptime) { V_ip6_log_time = time_uptime; log(LOG_DEBUG, "cannot forward " "from %s to %s nxt %d received on %s\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst), ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif)); } m_freem(m); return; } #ifdef IPSEC /* * Check if this packet has an active SA and needs to be dropped * instead of forwarded. */ if (ip6_ipsec_fwd(m) != 0) { IP6STAT_INC(ip6s_cantforward); m_freem(m); return; } #endif /* IPSEC */ #ifdef IPSTEALTH if (!V_ip6stealth) { #endif if (ip6->ip6_hlim <= IPV6_HLIMDEC) { /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ icmp6_error(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); return; } ip6->ip6_hlim -= IPV6_HLIMDEC; #ifdef IPSTEALTH } #endif /* * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - * size of IPv6 + ICMPv6 headers) bytes of the packet in case * we need to generate an ICMP6 message to the src. * Thanks to M_EXT, in most cases copy will not occur. * * It is important to save it before IPsec processing as IPsec * processing may modify the mbuf. */ mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); #ifdef IPSEC /* get a security policy for this packet */ sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, &error); if (sp == NULL) { IPSEC6STAT_INC(ips_out_inval); IP6STAT_INC(ip6s_cantforward); if (mcopy) { #if 0 /* XXX: what icmp ? */ #else m_freem(mcopy); #endif } m_freem(m); return; } error = 0; /* check policy */ switch (sp->policy) { case IPSEC_POLICY_DISCARD: /* * This packet is just discarded. */ IPSEC6STAT_INC(ips_out_polvio); IP6STAT_INC(ip6s_cantforward); KEY_FREESP(&sp); if (mcopy) { #if 0 /* XXX: what icmp ? */ #else m_freem(mcopy); #endif } m_freem(m); return; case IPSEC_POLICY_BYPASS: case IPSEC_POLICY_NONE: /* no need to do IPsec. */ KEY_FREESP(&sp); goto skip_ipsec; case IPSEC_POLICY_IPSEC: if (sp->req == NULL) { /* XXX should be panic ? */ printf("ip6_forward: No IPsec request specified.\n"); IP6STAT_INC(ip6s_cantforward); KEY_FREESP(&sp); if (mcopy) { #if 0 /* XXX: what icmp ? */ #else m_freem(mcopy); #endif } m_freem(m); return; } /* do IPsec */ break; case IPSEC_POLICY_ENTRUST: default: /* should be panic ?? */ printf("ip6_forward: Invalid policy found. %d\n", sp->policy); KEY_FREESP(&sp); goto skip_ipsec; } { struct ipsecrequest *isr = NULL; /* * when the kernel forwards a packet, it is not proper to apply * IPsec transport mode to the packet. This check avoid from this. * at present, if there is even a transport mode SA request in the * security policy, the kernel does not apply IPsec to the packet. * this check is not enough because the following case is valid. * ipsec esp/tunnel/xxx-xxx/require esp/transport//require; */ for (isr = sp->req; isr; isr = isr->next) { if (isr->saidx.mode == IPSEC_MODE_ANY) goto doipsectunnel; if (isr->saidx.mode == IPSEC_MODE_TUNNEL) goto doipsectunnel; } /* * if there's no need for tunnel mode IPsec, skip. */ if (!isr) goto skip_ipsec; doipsectunnel: /* * All the extension headers will become inaccessible * (since they can be encrypted). * Don't panic, we need no more updates to extension headers * on inner IPv6 packet (since they are now encapsulated). * * IPv6 [ESP|AH] IPv6 [extension headers] payload */ /* * If we need to encapsulate the packet, do it here * ipsec6_proces_packet will send the packet using ip6_output */ error = ipsec6_process_packet(m, sp->req); /* Release SP if an error occured */ if (error != 0) KEY_FREESP(&sp); if (error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We * will just continue to process the packet without * IPsec processing. */ error = 0; goto skip_ipsec; } if (error) { /* mbuf is already reclaimed in ipsec6_process_packet. */ switch (error) { case EHOSTUNREACH: case ENETUNREACH: case EMSGSIZE: case ENOBUFS: case ENOMEM: break; default: printf("ip6_output (ipsec): error code %d\n", error); /* FALLTHROUGH */ case ENOENT: /* don't show these error codes to the user */ break; } IP6STAT_INC(ip6s_cantforward); if (mcopy) { #if 0 /* XXX: what icmp ? */ #else m_freem(mcopy); #endif } return; } else { /* * In the FAST IPSec case we have already * re-injected the packet and it has been freed * by the ipsec_done() function. So, just clean * up after ourselves. */ m = NULL; goto freecopy; } } skip_ipsec: #endif again: bzero(&rin6, sizeof(struct route_in6)); dst = (struct sockaddr_in6 *)&rin6.ro_dst; dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_family = AF_INET6; dst->sin6_addr = ip6->ip6_dst; again2: rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m)); + rt = rin6.ro_rt; if (rin6.ro_rt != NULL) RT_UNLOCK(rin6.ro_rt); else { IP6STAT_INC(ip6s_noroute); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute); if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); } goto bad; } - rt = rin6.ro_rt; /* * Source scope check: if a packet can't be delivered to its * destination for the reason that the destination is beyond the scope * of the source address, discard the packet and return an icmp6 * destination unreachable error with Code 2 (beyond scope of source * address). We use a local copy of ip6_src, since in6_setscope() * will possibly modify its first argument. * [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1] */ src_in6 = ip6->ip6_src; if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) { /* XXX: this should not happen */ IP6STAT_INC(ip6s_cantforward); IP6STAT_INC(ip6s_badscope); goto bad; } if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) { IP6STAT_INC(ip6s_cantforward); IP6STAT_INC(ip6s_badscope); goto bad; } if (inzone != outzone) { IP6STAT_INC(ip6s_cantforward); IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard); if (V_ip6_log_time + V_ip6_log_interval < time_uptime) { V_ip6_log_time = time_uptime; log(LOG_DEBUG, "cannot forward " "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst), ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp)); } if (mcopy) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE, 0); goto bad; } /* * Destination scope check: if a packet is going to break the scope * zone of packet's destination address, discard it. This case should * usually be prevented by appropriately-configured routing table, but * we need an explicit check because we may mistakenly forward the * packet to a different zone by (e.g.) a default route. */ dst_in6 = ip6->ip6_dst; if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 || in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 || inzone != outzone) { IP6STAT_INC(ip6s_cantforward); IP6STAT_INC(ip6s_badscope); goto bad; } if (rt->rt_flags & RTF_GATEWAY) dst = (struct sockaddr_in6 *)rt->rt_gateway; /* * If we are to forward the packet using the same interface * as one we got the packet from, perhaps we should send a redirect * to sender to shortcut a hop. * Only send redirect if source is sending directly to us, * and if packet was not source routed (or has any options). * Also, don't send redirect if forwarding using a route * modified by a redirect. */ if (V_ip6_sendredirects && rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) { /* * If the incoming interface is equal to the outgoing * one, and the link attached to the interface is * point-to-point, then it will be highly probable * that a routing loop occurs. Thus, we immediately * drop the packet and send an ICMPv6 error message. * * type/code is based on suggestion by Rich Draves. * not sure if it is the best pick. */ icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); goto bad; } type = ND_REDIRECT; } /* * Fake scoped addresses. Note that even link-local source or * destinaion can appear, if the originating node just sends the * packet to us (without address resolution for the destination). * Since both icmp6_error and icmp6_redirect_output fill the embedded * link identifiers, we can do this stuff after making a copy for * returning an error. */ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { /* * See corresponding comments in ip6_output. * XXX: but is it possible that ip6_forward() sends a packet * to a loopback interface? I don't think so, and thus * I bark here. (jinmei@kame.net) * XXX: it is common to route invalid packets to loopback. * also, the codepath will be visited on use of ::1 in * rthdr. (itojun) */ #if 1 if (0) #else if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0) #endif { printf("ip6_forward: outgoing interface is loopback. " "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst), ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp)); } /* we can just use rcvif in forwarding. */ origifp = m->m_pkthdr.rcvif; } else origifp = rt->rt_ifp; /* * clear embedded scope identifiers if necessary. * in6_clearscope will touch the addresses only when necessary. */ in6_clearscope(&ip6->ip6_src); in6_clearscope(&ip6->ip6_dst); /* Jump over all PFIL processing if hooks are not active. */ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto pass; odst = ip6->ip6_dst; /* Run through list of hooks for output packets. */ error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); if (error != 0 || m == NULL) goto freecopy; /* consumed by filter */ ip6 = mtod(m, struct ip6_hdr *); /* See if destination IP address was changed by packet filter. */ if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { m->m_flags |= M_SKIP_FIREWALL; /* If destination is now ourself drop to ip6_input(). */ if (in6_localip(&ip6->ip6_dst)) m->m_flags |= M_FASTFWD_OURS; - else + else { + RTFREE(rt); goto again; /* Redo the routing table lookup. */ + } } /* See if local, if yes, send it to netisr. */ if (m->m_flags & M_FASTFWD_OURS) { if (m->m_pkthdr.rcvif == NULL) m->m_pkthdr.rcvif = V_loif; if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { m->m_pkthdr.csum_flags |= CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR; m->m_pkthdr.csum_data = 0xffff; } #ifdef SCTP if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; #endif error = netisr_queue(NETISR_IPV6, m); goto out; } /* Or forward to some other address? */ if ((m->m_flags & M_IP6_NEXTHOP) && (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { dst = (struct sockaddr_in6 *)&rin6.ro_dst; bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6)); m->m_flags |= M_SKIP_FIREWALL; m->m_flags &= ~M_IP6_NEXTHOP; m_tag_delete(m, fwd_tag); + RTFREE(rt); goto again2; } pass: /* See if the size was changed by the packet filter. */ if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) { in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); if (mcopy) { u_long mtu; #ifdef IPSEC size_t ipsechdrsiz; #endif /* IPSEC */ mtu = IN6_LINKMTU(rt->rt_ifp); #ifdef IPSEC /* * When we do IPsec tunnel ingress, we need to play * with the link value (decrement IPsec header size * from mtu value). The code is much simpler than v4 * case, as we have the outgoing interface for * encapsulated packet as "rt->rt_ifp". */ ipsechdrsiz = ipsec_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND, NULL); if (ipsechdrsiz < mtu) mtu -= ipsechdrsiz; /* * if mtu becomes less than minimum MTU, * tell minimum MTU (and I'll need to fragment it). */ if (mtu < IPV6_MMTU) mtu = IPV6_MMTU; #endif /* IPSEC */ icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu); } goto bad; } error = nd6_output_ifp(rt->rt_ifp, origifp, m, dst, NULL); if (error) { in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); IP6STAT_INC(ip6s_cantforward); } else { IP6STAT_INC(ip6s_forward); in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward); if (type) IP6STAT_INC(ip6s_redirectsent); else { if (mcopy) goto freecopy; } } if (mcopy == NULL) goto out; switch (error) { case 0: if (type == ND_REDIRECT) { icmp6_redirect_output(mcopy, rt); goto out; } goto freecopy; case EMSGSIZE: /* xxx MTU is constant in PPP? */ goto freecopy; case ENOBUFS: /* Tell source to slow down like source quench in IP? */ goto freecopy; case ENETUNREACH: /* shouldn't happen, checked above */ case EHOSTUNREACH: case ENETDOWN: case EHOSTDOWN: default: type = ICMP6_DST_UNREACH; code = ICMP6_DST_UNREACH_ADDR; break; } icmp6_error(mcopy, type, code, 0); goto out; freecopy: m_freem(mcopy); goto out; bad: m_freem(m); out: if (rt != NULL) RTFREE(rt); } Index: projects/release-pkg/sys/sys/ttydevsw.h =================================================================== --- projects/release-pkg/sys/sys/ttydevsw.h (revision 294447) +++ projects/release-pkg/sys/sys/ttydevsw.h (revision 294448) @@ -1,196 +1,197 @@ /*- * Copyright (c) 2008 Ed Schouten * All rights reserved. * * Portions of this software were developed under sponsorship from Snow * B.V., the Netherlands. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_TTYDEVSW_H_ #define _SYS_TTYDEVSW_H_ #ifndef _SYS_TTY_H_ #error "can only be included through " #endif /* !_SYS_TTY_H_ */ /* * Driver routines that are called from the line discipline to adjust * hardware parameters and such. */ typedef int tsw_open_t(struct tty *tp); typedef void tsw_close_t(struct tty *tp); typedef void tsw_outwakeup_t(struct tty *tp); typedef void tsw_inwakeup_t(struct tty *tp); typedef int tsw_ioctl_t(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); typedef int tsw_cioctl_t(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td); typedef int tsw_param_t(struct tty *tp, struct termios *t); typedef int tsw_modem_t(struct tty *tp, int sigon, int sigoff); typedef int tsw_mmap_t(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr, int nprot, vm_memattr_t *memattr); typedef void tsw_pktnotify_t(struct tty *tp, char event); typedef void tsw_free_t(void *softc); typedef bool tsw_busy_t(struct tty *tp); struct ttydevsw { unsigned int tsw_flags; /* Default TTY flags. */ tsw_open_t *tsw_open; /* Device opening. */ tsw_close_t *tsw_close; /* Device closure. */ tsw_outwakeup_t *tsw_outwakeup; /* Output available. */ tsw_inwakeup_t *tsw_inwakeup; /* Input can be stored again. */ tsw_ioctl_t *tsw_ioctl; /* ioctl() hooks. */ tsw_cioctl_t *tsw_cioctl; /* ioctl() on control devices. */ tsw_param_t *tsw_param; /* TIOCSETA device parameter setting. */ tsw_modem_t *tsw_modem; /* Modem sigon/sigoff. */ tsw_mmap_t *tsw_mmap; /* mmap() hooks. */ tsw_pktnotify_t *tsw_pktnotify; /* TIOCPKT events. */ tsw_free_t *tsw_free; /* Destructor. */ tsw_busy_t *tsw_busy; /* Draining output. */ void *tsw_spare[3]; /* For future use. */ }; static __inline int ttydevsw_open(struct tty *tp) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_open(tp); } static __inline void ttydevsw_close(struct tty *tp) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); tp->t_devsw->tsw_close(tp); } static __inline void ttydevsw_outwakeup(struct tty *tp) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); /* Prevent spurious wakeups. */ if (ttydisc_getc_poll(tp) == 0) return; tp->t_devsw->tsw_outwakeup(tp); } static __inline void ttydevsw_inwakeup(struct tty *tp) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); /* Prevent spurious wakeups. */ if (tp->t_flags & TF_HIWAT_IN) return; tp->t_devsw->tsw_inwakeup(tp); } static __inline int ttydevsw_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_ioctl(tp, cmd, data, td); } static __inline int ttydevsw_cioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_cioctl(tp, unit, cmd, data, td); } static __inline int ttydevsw_param(struct tty *tp, struct termios *t) { MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_param(tp, t); } static __inline int ttydevsw_modem(struct tty *tp, int sigon, int sigoff) { MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_modem(tp, sigon, sigoff); } static __inline int ttydevsw_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) { MPASS(!tty_gone(tp)); return tp->t_devsw->tsw_mmap(tp, offset, paddr, nprot, memattr); } static __inline void ttydevsw_pktnotify(struct tty *tp, char event) { tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); tp->t_devsw->tsw_pktnotify(tp, event); } static __inline void ttydevsw_free(struct tty *tp) { MPASS(tty_gone(tp)); tp->t_devsw->tsw_free(tty_softc(tp)); } static __inline bool ttydevsw_busy(struct tty *tp) { - MPASS(tty_gone(tp)); + tty_lock_assert(tp, MA_OWNED); + MPASS(!tty_gone(tp)); return (tp->t_devsw->tsw_busy(tp)); } #endif /* !_SYS_TTYDEVSW_H_ */ Index: projects/release-pkg/sys =================================================================== --- projects/release-pkg/sys (revision 294447) +++ projects/release-pkg/sys (revision 294448) Property changes on: projects/release-pkg/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r294408-294447 Index: projects/release-pkg =================================================================== --- projects/release-pkg (revision 294447) +++ projects/release-pkg (revision 294448) Property changes on: projects/release-pkg ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r294408-294447