text:
Henriette Tielemans
PDF Binder
Word Document Binder
Brussels +32 2 549 5252 htielemans@cov.com Download V-card
View Full Bio View Less
Described as "a league ahead" in Legal 500, Henriette (Jetty) Tielemans advises global companies on data protection and cybersecurity.
Ms. Tielemans focuses on international data transfers, binding corporate rules, big data, cloud computing, GDPR, e-discovery, consumer privacy, behavioural advertising, and mobile privacy issues.
Ms. Tielemans served on the board of directors of the International Association of Privacy Professionals and is the recipient of its 2018 Vanguard Award for leadership in the field of privacy. She currently serves on the editorial board of the Global Data Review (GDT).
Obtained approval of binding corporate rules for United Technologies and several other U.S.-based multinationals, including for processor rules and client-tailored transition measures.
Assisting an Asia-based multinational with complex global privacy compliance issues.
Assisted a U.S.-based multinational with allegations of privacy violations relating to screening for international trade sanctions.
Representing Facebook before the Brussels courts in on-going privacy litigation.
Detailed country by country analysis of subject access requests relating to performing evaluations.
Obtained authorization from the Dutch Supervisory Authority to deviate from standard contract clauses for international data transfers.
Assisting with GDPR audits.
Handicap International Belgium, Brussels based 1997 Nobel Peace Prize Winner: various professional advice.
The Arch, an international living community for mentally handicapped: occasional legal advice.
Memberships and Affiliations
Harvard Club of Belgium
European Harvard Law School Association
The Universitaire Instelling Antwerpen, Assistant Professor (1976-1977 and 1979-1980)
Trainee in international law firm in Hamburg, Germany (1980)
The Universite Nationale du Rwanda, Professor of Comparative Law (1980)
News and Insights (Showing 5 of 134) (Showing 134 of 134)
Paving The Way: Women In Data Survey
Media Mention
September 30, 2019, Global Data Review
China Releases Draft Amendments to the Personal Information Protection Standard
February 11, 2019, Covington Alert
On February 1, 2019, China's National Information Security Standardization Technical Committee ("TC260") released a set of amendments to GB/T 35273-2017 Information Technology – Personal Information Security Specification ("the Standard") for public comment. The comment period ends on March 3.
EU-Japan Adopt Mutual Adequacy Decision
January 24, 2019, Inside Privacy
[Update to previous post from August 17, 2018] On January 23, 2019, the European Commission and Japan mutually recognized each other's data protection laws as providing an adequate level of protection of personal data (see European Commission press release here). As a result, nearly all personal data can now flow freely between the EU and...… Continue Reading
Google fined €50 million in France for GDPR violation
On January 21, 2019, the French Supervisory Authority for data protection ("CNIL") issued a fine of €50 million against Google for violations of the General Data Protection Regulation ("GDPR") (the decision was published in French here). The CNIL's decision was triggered by complaints from two non-profit organizations together representing 9974 individuals. The ...
Google Fined €50Million in France for GDPR Violation
January 22, 2019, Covington Alert
On January 21, 2019, the French Supervisory Authority for data protection ("CNIL") issued a fine of €50 million against Google for violations of the General Data Protection Regulation ("GDPR") (the decision was published in French here).
China Privacy Developments in 2018
January 2, 2019, Covington Alert
The past year was a particularly significant one for the development of Chinese privacy law. During 2018, the Chinese government systematically established the country's regulatory requirements for cybersecurity and data privacy and continued to implement the Cybersecurity Law, which took effect on June 1, 2017.
GDPR Has Companies Big and Small Racing to Comply
May 24, 2018, The Wall Street Journal
Henriette Tielemans is quoted by The Wall Street Journal in an article regarding the upcoming deadline for companies to comply with the General Data Protection Regulation. "Companies are struggling with the concrete deliverables—the record of processing activities, the transfer agreements, the notices, the website—because of the sheer volume," says Tielemans. ...
What will happen on May 26? We asked Helen Dixon
April 3, 2018, IAPP
Henriette Tielemans participated in a session at the Global Privacy Summit and is quoted in an IAPP article regarding what happens once GDPR goes into effect. "For a lead regulator for the one-stop shop, you need a mean establishment. You lose a lot of the benefits of the GDPR if you're unable to come up with what your main establishment is," Tielemans said.
Irish Regulator To Eye Transparency In GDPR Enforcement
March 29, 2018, Law360
Henriette Tielemans spoke at an IAPP event and is quoted in a Law360 article regarding the Irish privacy authority's focus once GDPR takes effect. According to Tielemans, while "the GDPR has 150 articles, and businesses are worried about all 150 of them," companies are most concerned about the regulators' ability to issue massive fines of up to 4 percent of ...
Henriette 'Jetty' Tielemans honored as 2018 IAPP Privacy Vanguard Award winner
March 27, 2018, IAPP
Henriette Tielemans was the recipient of the 2018 IAPP Privacy Vanguard Award, a recognition reserved for individuals who display "exceptional leadership, knowledge, and creativity in the field of privacy and data protection."
Covington's Henriette Tielemans Receives Prestigious Data Privacy Award
BRUSSELS—Henriette Tielemans, co-chair of Covington's global Data Privacy and Cybersecurity practice, has today received the IAPP Privacy Vanguard Award, the industry's top honor, for her lifelong services to the data privacy community. The International Association of Privacy Professionals (IAPP) is the world's largest and most comprehensive global information ...
EU Commission Concludes Privacy Shield "Adequate" in first Annual Review
October 18, 2017, Covington Alert
The European Commission published its Report today on the first-annual review of the EU-U.S. Privacy Shield (the Report is accompanied with a Staff Working Document, Infographic, and Q&A).
The EU Gets Serious About Cyber: The EU Cybersecurity Act and Other Elements of the "Cyber Package"
September 18, 2017, Covington Alert
Last week, in his annual State of the European Union Address, the President of the European Commission Jean-Claude Juncker called out cybersecurity as a key priority for the European Union in the year ahead. In terms of ranking those priorities, President Juncker placed tackling cyber threats just one place below the EU leading the fight against climate change, ...
China Seeks Comments on Updated Draft of Cross-Border Data Transfer Security Assessment Standard
August 31, 2017, Covington Alert
On August 31, 2017, China's National Information Security Standardization Technical Committee ("NISSTC"), a standard-setting committee jointly supervised by the Standardization Administration of China ("SAC") and the Cyberspace Administration of China ("CAC"), released an updated draft of the Information Security Technology - Guidelines for Data Cross-Border ...
Are You Ready for the GDPR? A Practical Checklist for Employers
May 24, 2017, Covington Alert
On May 25, 2018, employers located or with staff in the European Union ("EU") will have to comply with a new data protection law—Regulation (EU) 2016/679 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data—commonly referred to as the General Data Protection Regulation ("GDPR"). This will ...
China Releases Near-final Draft of Regulation on Cross-border Data Transfers
On May 19, 2017, the Cyberspace Administration of China ("CAC") invited international stakeholders to attend a seminar to discuss an updated version of the Measures on Security Assessment of Cross-border Data Transfer of Personal Information and Important Data ("the Measures"). Given that the Measures have an intended effective date of June 1, 2017, it is likely ...
China Seeks Public Comments on Draft Regulation of Cross-Border Data Transfer
April 12, 2017, Covington Alert
On April 11, 2017, the Cyberspace Administration of China ("CAC") released a draft of the Measures on Security Assessment of Cross-border Data Transfer of Personal Information and Important Data ("the Draft Measures") for public comment (official Chinese version available here; Covington's translation of the Draft Measures is appended at the end of this alert).
How Merck Achieved BCRs and CBPRs Simultaneously
April 14, 2016, Inside Privacy
Merck & Co. recently became the first company to achieve simultaneous approval for its cross-border data transfer strategies through binding corporate rules (BCRs) under principles of the European Union and the cross-border privacy rules (CBPR) process under principles of the Asia-Pacific Economic Cooperation region. Subscribers to Law360 learned how Merck ...
Article 29 Working Party Reacts to the U.S.-EU Privacy Shield Agreement
February 3, 2016, Inside Privacy
On February 3rd, the Article 29 Working Party, representing Europe's data protection authorities, published its reaction to the announcement of a new "Privacy Shield" political agreement between the European Commission and the U.S. Government. The Privacy Shield agreement, announced on February 2nd (and further described in our blog post here), is intended to ...
EU and US in race to rewrite data sharing agreement as deadline passes
February 1, 2016, The Guardian
Henriette Tielemans is quoted by The Guardian in an article discussing the missed Safe Harbor deadline. According to Tielemans, companies faced "enormous uncertainty" about what European regulators would deem adequate privacy protection.
EU Court Draws Fine Line for Employee Monitoring Programs
January 15, 2016, Law360
Henriette Tielemans is quoted in a Law360 article discussing the recent European Court of Human Rights' decision allowing employers in the EU to monitor their employees' online activities for business purposes. "This decision is important," according to Tielemans. "It will bring much needed legal certainty in an area that many companies are struggling with."
GDPR: Key Elements for Businesses in All Sectors
December 21, 2015, Covington Alert
On December 15, the EU institutions finally agreed the text of the new EU data protection law, the General Data Protection Regulation ("GDPR"), completing a process that began in January 2012. The LIBE committee has published the consolidated version of the GDPR text. The GDPR heralds a new era of data protection. It replaces the existing data protection ...
E.U. Court Declares Data-Transfer Pact With U.S. Invalid
October 13, 2015, Bloomberg BNA
Henriette Tielemans is quoted in this BNA article that explores the idea of finding alternative means for the transfer of data with the elimination of Safe Harbor. Countries that require national data protection authority approval may find even more issues arise when trying to formulate new ways to navigate data transfer laws. Tielemans notes that the process ...
Safe Harbor: The European Court of Justice Ruling and Beyond. What's Next?
Presentation and Speech
October 8, 2015, Webinar
EU's Highest Court Invalidates Safe Harbor with Immediate Effect
October 6, 2015, Inside Privacy
Today, the Court of Justice of the European Union (the "CJEU") invalidated the European Commission's Decision on the EU-U.S. Safe Harbor arrangement (Commission Decision 2000/520 – see here). The Court responded to pre-judicial questions put forward by the Irish High Court in the so-called Schrems case. More specifically, the High Court had enquired, in ...
Europe's Top Court Just Gave U.S. Tech Firms a Huge Headache
October 6, 2015, Fortune
Brussels-based partner Henriette Tielemans is quoted in this Fortune article that discusses the effects of the highest E.U. court eliminating the U.S.-E.U. data transfer agreement known as the Safe Harbor Act. "Hindsight is a beautiful thing," said Tielemans. "We must all remember that in 2015 things are different than they were in 2000."
The EU's Highest Court Invalidates Safe Harbor with Immediate Effect
October 6, 2015, Covington Alert
Advocate General Considers EU-U.S. Safe Harbor to be Invalid
September 23, 2015, Inside Privacy
This morning (September 23, 2015), EU Advocate General ("AG") Bot issued an Opinion in Case C-362/14 Maximilian Schrems v Data Protection Commissioner (see our earlier post on the hearing here). The AG Opinion has gone further than expected, covering not just the power of national data protection authorities in relation to complaints under the Safe...… Continue ...
The EU General Data Protection Regulation: What's Next and What It Means For Your Business
July 1, 2015, Webinar
Chambers Europe and Legal 500 EMEA Recognise Covington in 20 Areas
BRUSSELS, June 11, 2015 — Covington has received 20 leading practice group rankings in the 2015 editions of Chambers Europe and Legal 500 EMEA. The legal guides have recognised the firm's expertise in the following areas: CHAMBERS EUROPE Europe-wide - Regulatory - Agro/Food Europe-wide - Regulatory - Environment Europe-wide - Regulatory - ...
The EUs Digital Single Market Strategy
May 6, 2015, Covington E-Alert
Covington's Brussels harvest
September 22, 2014, Commercial Dispute Resolution
Covington's Peter Camesasca, Johan Ysewyn, Melissa Van Schoorisse, Miranda Cole, Henriette Tielemans, Sebastian Vos, and Jean De Ruyt are mentioned in this article on the growth of Covington's Brussels office: "April was a busy month for Covington & Burling's competition lawyers, marking, as it did, the welcome return of Peter Camesasca – who temporarily ...
Client Event: "Data Protection & Privacy Law – 2nd Edition," September 23, 2014
Covington will be hosting a book launch for the 2014 title 'Data Protection & Privacy Law 2nd Edition', edited by Monika Kuschewsky, in partnership with The European Lawyer (Thomson Reuters) on September 23, 2014 in Brussels. The event will comprise a half-day workshop followed by a drinks reception. We are pleased to confirm that the...… Continue Reading
New EU Competition Commissioner - Margrethe Vestager
September 10, 2014, Covington E-Alert
Covington Wins Two 'European Women in Business Law' Awards
LONDON, 7 July, 2014 — Euromoney Legal Media Group awarded Covington partners Lisa Peets and Carmen Martinez Lopez the 'Best in Copyright' and 'Rising Star - Litigation' awards at the annual European Women in Business Law Awards ceremony in London. The awards honour firms that set "the standard in terms of female-friendly work practices, and women leading the ...
Nine Covington Lawyers Shortlisted for 'Europe Women in Business Law' Awards
LONDON, 1 May, 2014 — Euromoney Legal Media Group have shortlisted nine Covington lawyers for the annual 'Europe Women in Business Law Awards' 2014. Those shortlisted for "Best in" their respective practice areas are: Competition and Antitrust - Miranda Cole Copyright - Lisa Peets Financial Regulation - Charlotte Hill Life ...
Covington Strengthens EU Competition Practice with Johan Ysewyn and Peter Camesasca
Brussels, 30 April, 2014 — Covington & Burling is pleased to announce that Johan Ysewyn and Peter Camesasca are joining the firm's Brussels office as partners, where they will play substantial roles in the firm's global antitrust and competition practice. The additions of Mr. Ysewyn and Dr. Camesasca will strengthen the firm's existing EU competition team in ...
U.S. To Review Safe Harbor Program
March 26, 2014, Inside Privacy
As part of an ongoing European tour, President Obama has met with several EU political leaders in Brussels today. After the meeting, Herman van Rompuy, President of the EU, stated that the US has agreed to review the Safe Harbor. There are no further details known at this stage but most likely the changes will be...… Continue Reading
Dissuading Companies from Violating Data Protection Rules: Senior European Commission Official Calls for 'Significant' Fines
February 12, 2014, Inside Privacy
Speaking at Berkeley's Online Tracking Workshop today, Françoise Le Bail, Director-General of the European Commission's DG Justice (the leading department regarding the EU data protection reforms) confirmed the European Commission's vision that the EU needs stronger penalties in order to ensure effective enforcement of European data protection rules. Ms. Le Bail ...
The Future of the Safe Harbor Agreement
Recent events in the European Parliament and European Council demonstrate that concerns over the U.S.-EU Safe Harbor Agreement are continuing to mount, and reform or even revocation of the Safe Harbor Agreement remains a possibility. Today, Covington published a client alert that discusses recent developments involving the Safe Harbor Agreement and the ...
January 22, 2014, Covington E-Alert
From Privacy Professional to Privacy for Professionals: Expanding Privacy Beyond the Office of the CPO/DPO
January 2014, 7th International Conference on Computers, Privacy and Data Protection, Brussels
Privacy, Content, Ethics and Big Data
December 2013, Competition Summit, Brussels
European Commission Issues Six Point Policy Response to U.S. Surveillance Programs; Supports Reform of U.S.-EU Safe Harbor
November 27, 2013, Covington E-Alert
Analysing LIBE's Draft of the EU Data Protection Regulation
November 2013, IAPP Webinar
What Companies Need to Know About the European Parliament's Proposed Amendments to the Draft EU General Data Protection Regulation
October 24, 2013, Covington E-Alert
BTI Names Martin and Tielemans 'Client Service All-Stars'
WASHINGTON, DC, February 26, 2013 — The BTI Consulting Group has named Covington & Burling partners David Martin and Henriette Tielemans to its 2013 "Client Service All-Stars" list. The BTI "Client Service All-Stars" were singled out by general counsel and direct reports at large and Fortune 1000 organizations in one-on-one interviews. Mr. Martin, based in ...
Covington's Tielemans to IAPP Executive Committee
BRUSSELS, 5 February, 2013 — The International Association of Privacy Professionals, the world's largest association of privacy professionals, has appointed Covington & Burling's Henriette ("Jetty") Tielemans to its executive committee. "I am thrilled to welcome Jetty to our executive committee," said J. Trevor Hughes, president and CEO of IAPP. "Her expertise ...
Covington Named 'Privacy & Consumer Protection Practice Group of the Year'
WASHINGTON, DC, January 22, 2013 — For the second straight year, Law360 named Covington & Burling's global privacy and data security practice as one of the top five "Privacy & Consumer Protection Practice Groups of the Year." In a profile highlighting the firm's privacy-related work, Law360 noted the group's recent litigation win for LinkedIn Corp. In that case, ...
The Proposed EU Data Protection Regulation
October 2012, Benelux General Counsel Dinner, Brussels
Privacy Considerations for EU Cloud Clients
September 2012, IAPP Webinar
Update on the Reform of the European Data Protection Framework
March 27, 2012, Covington E-Alert
The New EU Data Protection Framework
February 2012, IAPP Webinar
Reform of the European Data Protection Framework
Law360 Names Covington 'Privacy & Consumer Protection Practice Group of the Year'
WASHINGTON, DC, January 9, 2012 — Law360 named Covington & Burling's global privacy & data security practice as one of the top five "Privacy & Consumer Protection Practice Groups of the Year." In a profile about the firm published on Jan. 5th, Law360 pointed to Covington's broad practice in assisting clients in transactions, on advisory matters, in social ...
IAPP Europe Data Protection Congress
November 29, 2011, When International Anti-corruption and Fraud Statutes Conflict with Data Protection Laws: Overcoming the Challenges
Q&A With Covington's Henriette Tielemans
September 14, 2011, Law360
Henriette Tielemans participated in this Q&A on privacy and consumer protection.
No place to hide
September 2011, European Lawyer
European Regulators Continue to Struggle With New Cookie Rule
June 17, 2011, Inside Privacy
In 2009, Directive 2002/58/EC, the so-called ePrivacy Directive, was amended. The deadline for EU Member States to implement the revised Directive in their national laws was May 25, 2011, but very few Member States met the deadline and even today, almost one month after the deadline, discussions remain ongoing in most national parliaments. The implementation ...
Covington Advises Microsoft in $8.5 Billion Skype Deal
WASHINGTON, SAN FRANCISCO, BRUSSELS, AND LONDON, May 10, 2011 —Covington & Burling LLP is advising Microsoft Corp. in its acquisition of Skype Global S.à.r.l., the leading Internet communications company, for $8.5 billion in cash. Microsoft's purchase of Skype from the investor group led by Silver Lake is expected to increase the accessibility of real-time ...
European Commission Adopts Evaluation Report on Data Retention Directive
Today the European Commission adopted an evaluation report on the Data Retention Directive. This Directive requires EU Member States to ensure that telecommunications service providers retain certain categories of data for the purpose of investigations, detection and prosecution of serious crime, as defined by the national law of the Member States. Since its ...
PNR Data in the Spotlight
March 10, 2011, Covington Advisory
EU's Hustinx: Data Protection Law Sanctions Should Mirror Competition Law
At a recent presentation in Frankfurt, Peter Hustinx, head of the European Data Protection Supervisor Office in Brussels, launched an intriguing idea: sanctioning violations of data protection law in the same manner as violations of competition law. The trade press regularly reports on multi-million euro fines for cartels or abuses of dominant positions by ...
Cloud Computing Continues to Loom Large on the International Data Privacy Agenda
February 15, 2011, EuroWatch
February 10, 2011, Covington Advisory
EU Data Retention Directive in Spotlight
December 24, 2010, Covington Advisory
UK Information Commissioner Wields First Fines for Violations of Data Protection Act
International Data Privacy Update November 2010
November 9, 2010, Covington Advisory
New Financial Reform Bill Includes Two Provisions Aimed at Curbing Corruption
July 21, 2010, Covington E-Alert
International Data Privacy Update June 2010
June 15, 2010, Covington Advisory
The New EU Rules For Online Sales
May 24, 2010, Competition Law360
European Commission Revises Distribution Rules
April 27, 2010, Inside EU Life Sciences
Originally published as Covington E-Alert on April 27, 2010 On 20 April 2010, the European Commission published new rules governing so-called "vertical" agreements, such as distribution and supply agreements. The new rules are set out in the Vertical Restraints Block Exemption Regulation and the related Guidelines (see DG Competition's website). They will ...
April 27, 2010, Covington E-Alert
Article 29 Working Party Announces Work Programme for 2010-11
Revised Model Clauses for Transfers to Processors in Non-Eea Countries
March 1, 2010, Covington Advisory
Google Executives Convicted in Landmark Privacy Case
UK to Issue Fines of Up to £500,000 for Violations of Data Protection Act
February 9, 2010, Covington E-Alert
The Lisbon Treaty and Data Protection: What's Next for Europe's Privacy Rules?
January/February 2010, The Privacy Advisor
EU Developments - Update on Changes to E-Privacy Directive
January 5, 2010, Covington Advisory
Striking A Balance
November/December 2009, The European Lawyer
November 23, 2009, Covington Advisory
Summary of October 1 Privacy & Data Security Workshop
October 2, 2009, Covington Advisory
Commission Takes Major Step Towards Re-opening Data Protection Directive
October 2009, The Privacy Advisor
EU–Recent Developments in European Data Protection Laws
September 30, 2009, EuroWatch
Recent Developments in European Data Protection Laws
September 22, 2009, Covington Advisory
Europe's Emerging Breach Notification Regime
April 2009, Privacy Laws & Business International
Covington's Tielemans Appointed to European Commission's Data Protection Expert Group
BRUSSELS, November 12, 2008 — Covington & Burling LLP partner Henriette Tielemans has been appointed to the Data Protection expert group (GEX PD) by the European Commission. The Data Protection expert group will assist the Commission in identifying challenges for the protection of personal data in the EU, and putting forward proposals for addressing those ...
Privacy Rules Do Not Trump IP Protection
May 1, 2008, Copyright World
The Concept of Personal Data in the European Union
REACH and Its Impact on Cosmetics
January 2007, Covington E-Alert
The Transfer of Airline Passenger Data to the U.S.: An Analysis of the ECJ Decision
June 2006, BNA International World Data Protection Report
Recent Guidance: Use of Consent for Data Transfers Outside the EU, Whistle-Blower Hotlines and EU Privacy Rules
April 10, 2006, The Bureau of National Affairs, Inc.'s Privacy & Security Law Report
Use of Consent for Data Transfers Oustside the EU, Whistle-Blower Hotlines and EU Privacy Rules
April 10, 2006, BNA Inc - Privacy and Security Law Report
Whistleblower Schemes under Sarbanes Oxley and EU Privacy Rules
Is Consent No Longer a Valid Basis for Transfers of Personal Data from the E.U. to the U.S.?
January 2006, BNA International: World Data Protection Report
Consent No Longer a Valid Basis for Transfer of Personal EU Data to the U.S.?
December 2005, Covington E-Alert
The Position of the Data Controller
December 2005, Workshop on International Data Transfers, organized by the Art. 29 Working Party and the U.S. Department of Commerce
Sox vs. CNIL - Light at the End of the Tunnel
11/18/2005, Covington E-Alert
Harmonizing EU Data Protection Law - A Long Way To Go
October 2005, ABA Section on International Law - Data Privacy Panel
Harmonization of EU Privacy Laws in the Member States: A Slow Process
October 2005, ABA International Section, Fall Meeting
Cybercrime:Data Security Aspects
April 2005, Laurence Simmons' General Counsel Dinner and Seminar, Benelux
EU Data Privacy Developments: IPR Enforcement and RFID
February 23, 2005, Covington E-Alert
EU Data Privacy Developments
EU Data Privacy Notices
January 2005, World Data Protection Report
December 10, 2004, Covington E-Alert
EU Commission Safe Harbour Report
November 1, 2004, Covington E-Alert
EU Data Protection Developments
Implementation of EU Directive 95/46 in France & Commission Review of UK Law
Data Retention and Spam
June 18, 2004, Covington E-Alert
New California Privacy Laws to Take Effect
May 21, 2004, Covington E-Alert
Article 29 Opinions on EU "Spam" Rules, Passenger Data and Video Surveillance
March 5, 2004, Covington E-Alert
The Impact of the European Union's Privacy Directive on U.S. Companies
March 2004, presentation at the Manufacturers Alliance for Productivity and Innovation
EU Communication on Spam
International Product Distribution: An EU Perspective
2004, presentation at the ABA, Antitrust Section, Spring Meeting
Alternative Contract Clauses for Data Transfers and Resolution of Airline Passenger Data Disputes
ECJ Judgement in Lindqvist Case & Implementation of New EU Directive
Reform of Data Protection Notification Requirements
October 2, 2003, Covington & Burling Client Report
Adequacy Determination for Argentina and Development in Central & Eastern Europe
Commission Reports on EU Directive
May 2003, Covington E-Alert
Structuring Sales Arrangements for Branded Goods in an Enlarged Europe
May 2003, presentation at Laurence Simons' The General Counsel Dinner & Seminar - Consumer, Retail & Branded Goods
Privacy Standardization
EU Data Protection Legislation: Challenges with Compliance
November 2002, Covington & Burling's Data Protection Conference
A Changed System: Proposed Reform of European Commission Review Has Foreseeable Problems
November 13, 2000, Legal Times
Proposed Reforms of EC Competition Law
2000, 15 Antitrust 65
EC Anti-Dumping Policy
1992, Journal of the Japanese Institute of International Business Law, Volume 20, No. 1, p. 35 and No. 2, p. 167
Upcoming Changes in the 'Common Market' Cosmetic
September 1991, Legislation Food, Drug, Cosmetic and Medical Device Law Digest, 3, p. 14
EC Trade Relations with Japan
1991, Journal of the Japanese Institute of International Business Law, Volume 19, No. 12, p. 1536
Annuary, Handelspraktijken/Pratiques du Commerce
1988, Trade Practices
The Termination of Agency and Distributorship Agreements: A Comparative Survey
1981, Northwestern Journal of International Law and Business, Vol. 2, pp. 452-495
Tax Free Mergers Under Belgian Law
1980, International Tax Report, No. 80-7, p. 3
Euromoney Legal Media Group, shortlisted for Europe Women in Business Law Awards for Privacy and Data Protection (2018) and TMT (2014)
Chambers Global, Data Protection (2008-2017)
Chambers Europe, Data Protection (2015-2019)
Legal 500 EMEA
EU Regulatory, Privacy & Data Protection (2010-2017)
EU Regulatory, Information Technology (2016)
IT and Telecoms (2016)
Competition - Belgium (2010)
IAM Patent 1000 - The World's Leading Patent Practitioners (2012-2015)
BTI Client All Stars (2013)
Elected to Board of International Association of Privacy Professionals (IAPP)
Litigation and Investigations
Regulatory and Public Policy
Antitrust/Competition
Data Privacy and Cybersecurity
Cross-Border Transfers
Harvard Law School, LL.M., 1978
Frank Boas Fellowship for International Legal Studies
Fulbright Fellow
University of Antwerp, Belgium, J.D., 1976
University of Antwerp, Belgium, B.A., 1973


text:
Q: Criar certificado de lançamento sha1 Xamarin Forms Olá, tenho um projeto em c# em Xamarin Forms. Estou usando um api do Google maps e durante a depução ele funciona normalmente, porém a chave para o uso do mapa é para apenas testes. Segui as orientações para criar uma chave para distribuição, mas não consegui resultado. Na imagem mostra as orientações. e no link abaixo, a orinetação da Microsoft.
inserir a descrição da imagem aqui
Link do site da Microsoft: https://learn.microsoft.com/en-us/xamarin/android/deploy-test/signing/keystore-signature?tabs=windows
Ao seguir os passos, dá erro não encontrando minha solicitação.
inserir a descrição da imagem aqui

redpajama_set_name: RedPajamaStackExchange


BiQ Analyzer is Java-based and runs on almost any operating system, including Windows, MacOS, Linux and Solaris. However, it requires a recent Java version. Let's check this first: Start a command line (Windows: type "cmd" or "command" in the "Start"->"Run" dialog) or a shell window and enter "java -version" to find out your Java version. If it's 1.5 or above, everything is fine and you can directly continue to step 2. If you receive an error message or a version number below 1.5, you have to install a recent version of Java first. You can download it for free from http://www.java.com/. Install it as described and then proceed to step 2.
Go to the download page, fill out the text fields, tick the box that you accept the license agreement and download the installer.
Windows, MacOS and Solaris users run the installer by double-clicking on the "install BiQ Analyzer.jar" file. Linux users might have to open a shell and continue as follows. Change to the directory where you saved the "install_BiQ_Analyzer.jar" file ("cd your/path/...") and enter "java -jar install_BiQ_Analyzer.jar". After the installer has been started, follow the instructions.
After successful installation, you can either click the BiQ Analyzer icon in the start menu or go to BiQ Analyzer's installation directory and double-click on "BiQ Analyzer.jar", which will start BiQ Analyzer. If you are having trouble starting BiQ Analyzer, please try the following: Open a command line (Windows: type "cmd" or "command" in the "Start"->"Run" dialog) or a shell window, go the the BiQ Analyzer directory ("cd your/path/...") and type "start_BiQ_Analyzer_win.bat" (Windows) or "sh start_BiQ_Analyzer_unix.sh" (MacOS, Linux, Unix). If an error message is displayed and the window immediately closes, please type "start_BiQ_Analyzer_view_error_messages_win.bat" (Windows) or "start_BiQ_Analyzer_view_error_messages_unix.sh" (MacOS, Linux, Unix) instead to view the error message.
On the first start, BiQ Analyzer will open the configuration editor and ask you to complete missing information. In particular, you should tell BiQ Analyzer which chromatogram file editor it should use (e.g. Chromas LITE), in order to be able to go back to the raw chromatograms. If you don't want to use a chromatogram editor, just cancel and click "No" in the following dialog. You can return to the configuration editor at a later stage by pressing the "Config" button on the bottom left of the main screen.
Now it is a good idea to go through the Guided Tour yourself, using the demonstration data that is provided in the program directory. This will not only make sure that everything is working as it should, it will also give you the most efficient introduction into how to use the BiQ Analyzer.
If you have any troubles, please look into the Troubleshooting / FAQ section. If this does not solve your problem, feel free to contact us - but be sure to provide extensive information about your problem, if possible also screenshots that show the problem.


Lucie has a recurring dream, where she falls deeper and deeper into a never-ending vacuum, drawn irresistibly by a blinding star. When she is awake, she sees lights flashing in her field of vision, altering her consciousness.
Her parents are worried. Doctors try to find an explanation and a cure. Where does this star come from, shining brighter than any other? What obscure corner of our life do these passionate flashes try to shed light on?


Motorola ATRIX 4G (Unlocked Quadband) Touchscreen GSM Cell PhoneIf you have been looking for a phone that may act like your personal computer, here is the amazing option for your. Motorola Atrix MB860 4G is an amazing phone which delivers the best of power and performance, when it comes to mobile computing and at the same time, it fits comfortably in your pocket. With the help of Motorola Atrix MB860, you know have the freedom to browse the web browser, and access all of your crucial emails, photos, movies and other files while moving about with your phone.
Below we shall discuss various features of Motorola Atrix MB860 phone.
Impeccable security features – the Motorola Atrix is pretty smart on the security front. It has a finger print recognition technology, which means that only the one with the registered finger print can access it. This security feature is faster and enhances and obviously is superior to password or PIN lock systems.
Dual core technology – just like your computer, even the processor of Motorola Atrix MB860 is dual core and hence makes everything appear much faster. Just like you computer, you can easily listen to your choice of music, browser internet and send emails etc, effortlessly, with the help of this phone.
Clear display – the display of the phone is amazing and simply spectacular, with its crisp and rich 24 but color and qHD display for the smart phone. With this kind of display, the phone gets remarkable clarity and you get to enjoy this feature while playing games, watching TV shows, pictures and images and a lot more.
Face to face conversations – if you really need to make an urgent face to face call, you can easily do that with your Motorola Atrix MB860 4G phone. With its front facing camera, Motorola Atrix supports face to face chats and hence you can switch to the video mode with its 5 mega pixel camera.
Big screen clarity for HD videos – with the help of Motorola Atrix, you can watch you favorite shows on computer or big screen or on your phone. Also, you get to watch videos in High Definition.
PC connections and we surfing – Motorola Atrix allows you to easily access your computer, through any remote location. Also, you can easily surf the internet and enjoy a rich web browsing experience with the help of its web top application.
End note – thus, for all of your business and recreational purposes, get Motorola Atrix MB860 4G phone ASAP.


Australian family favourites The Wiggles bring their Wiggle Fun Tour! to Melbourne Recital Centre this July.
The Wiggles are back and performing for you as part of their Wiggle Fun Tour! This brand-new show sees Emma, Lachy, Anthony and Simon singing and dancing their way around Australia with all their Wiggly friends, including Captain Feathersword, Dorothy the Dinosaur, Wags the Dog, Henry the Octopus and their brand new friend, Shirley Shawn the Unicorn.
This is your chance to experience all the fun of The Wiggles show in person. Join us and be a part of the Wiggle Fun Tour! With so many sold out shows last year, you better get a wiggle on and get your tickets now as tickets to the Wiggle Fun Tour! will sell like hot potatoes!
The performance at 10am Sunday 7 July will be Auslan interpreted.
You can book up to 6 tickets online. Please call the Box Office on (03) 9699 3333 to reserve 7+ tickets.
Babies under the age of 12 months may attend this concert free of charge and be admitted without a ticket, on the condition that they do not occupy a seat and sit on the lap of a parent or guardian.
Tickets for this concert will be in very high demand and you may be placed into our online 'Waiting Room' to purchase tickets. This helps ensure your website experience is as smooth as possible. Thanks in advance for your patience.


text:
package com.sequenceiq.cloudbreak.ccm.cloudinit;

import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_AGENT_BACKEND_ID_PREFIX;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_AGENT_CERTIFICATE;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_AGENT_CRN;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_AGENT_ENCIPHERED_KEY;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_AGENT_KEY_ID;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_INVERTING_PROXY_CERTIFICATE;
import static com.sequenceiq.cloudbreak.ccm.cloudinit.CcmV2ParameterConstants.CCMV2_INVERTING_PROXY_HOST;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;

public class DefaultCcmV2ParametersTest {

    private DefaultCcmV2Parameters underTest;

    @Test
    public void testAddToTemplateModel() {
        underTest = new DefaultCcmV2Parameters("invertingProxyHost", "invertingProxyCertificate", "agentCrn",
                "agentKeyId", "agentEncipheredPrivateKey", "agentCertificate");

        Map<String, Object> expectedParams = new HashMap<>();
        underTest.addToTemplateModel(expectedParams);

        assertEquals(7, expectedParams.size(), "CcmV2 Paramters size should match");
        assertEquals("invertingProxyHost", expectedParams.get(CCMV2_INVERTING_PROXY_HOST), "CcmV2 InvertingProxy Host should match");
        assertEquals("agentCrn", expectedParams.get(CCMV2_AGENT_CRN), "CcmV2 AgentCrn should match");
        assertEquals("agentCrn-", expectedParams.get(CCMV2_AGENT_BACKEND_ID_PREFIX), "CcmV2 Agent BackendId Prefix should match");
        assertEquals("agentKeyId", expectedParams.get(CCMV2_AGENT_KEY_ID), "CcmV2 AgentKeyId should match");

        assertEquals("invertingProxyCertificate",
                expectedParams.get(CCMV2_INVERTING_PROXY_CERTIFICATE), "CcmV2 InvertingProxy Cert should match");

        assertEquals("agentEncipheredPrivateKey",
                expectedParams.get(CCMV2_AGENT_ENCIPHERED_KEY), "CcmV2 Agent Enciphered Private Key should match");

        assertEquals("agentCertificate", expectedParams.get(CCMV2_AGENT_CERTIFICATE), "CcmV2 Agent Certificate should match");
    }
}

redpajama_set_name: RedPajamaGithub


Taiwan: The city government of Taoyuan has awarded a contract for the delivery of electrical and mechanical systems for the Green Line of its metro network to a consortium. The group includes Siemens Mobility and two further companies: Hyundai Rotem, a train manufacturer in South Korea and BES Engineering, which is based in Taiwan.
The project features the installation of a signalling system which facilitates GoA (Grade of Automation) 4 autonomous train operation. Siemens will provide its Trainguard MT Communications-Based Train Control system (CBTC), traction drives for the trains and the direct-current (DC) traction power supply for the line.
On completion the line will be 27.8 km long. 12.5 km of it will be underground and approximately 15.3 kilometers will be elevated. The Green Line will connect Taoyuan City with Taoyuan International Airport and Aerotropolis, a planned urban development around the airport, via the TTY Airport Line.
The city government is also planning extensions for two other lines: from Taoyuan to Daxi, including three new stations, and from Taoyuan to Chungli, with seven new stations.


text:
#include <linux/bootmem.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/genalloc.h>
#include <linux/gfp.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/slab.h>
#include <linux/iommu.h>
#include <linux/io.h>
#include <linux/vmalloc.h>
#include <linux/sizes.h>
#include <linux/cma.h>

#include <asm/memory.h>
#include <asm/highmem.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/mach/arch.h>
#include <asm/dma-iommu.h>
#include <asm/mach/map.h>
#include <asm/system_info.h>
#include <asm/dma-contiguous.h>

#include "dma.h"
#include "mm.h"

/*
 * The DMA API is built upon the notion of "buffer ownership".  A buffer
 * is either exclusively owned by the CPU (and therefore may be accessed
 * by it) or exclusively owned by the DMA device.  These helper functions
 * represent the transitions between these two ownership states.
 *
 * Note, however, that on later ARMs, this notion does not work due to
 * speculative prefetches.  We model our approach on the assumption that
 * the CPU does do speculative prefetches, which means we clean caches
 * before transfers and delay cache invalidation until transfer completion.
 *
 */
static void __dma_page_cpu_to_dev(struct page *, unsigned long,
		size_t, enum dma_data_direction);
static void __dma_page_dev_to_cpu(struct page *, unsigned long,
		size_t, enum dma_data_direction);

/**
 * arm_dma_map_page - map a portion of a page for streaming DMA
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @page: page that buffer resides in
 * @offset: offset into page for start of buffer
 * @size: size of buffer to map
 * @dir: DMA transfer direction
 *
 * Ensure that any data held in the cache is appropriately discarded
 * or written back.
 *
 * The device owns this memory once this call has completed.  The CPU
 * can regain ownership by calling dma_unmap_page().
 */
static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
	     unsigned long offset, size_t size, enum dma_data_direction dir,
	     struct dma_attrs *attrs)
{
	if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
		__dma_page_cpu_to_dev(page, offset, size, dir);
	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
}

static dma_addr_t arm_coherent_dma_map_page(struct device *dev, struct page *page,
	     unsigned long offset, size_t size, enum dma_data_direction dir,
	     struct dma_attrs *attrs)
{
	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
}

/**
 * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @handle: DMA address of buffer
 * @size: size of buffer (same as passed to dma_map_page)
 * @dir: DMA transfer direction (same as passed to dma_map_page)
 *
 * Unmap a page streaming mode DMA translation.  The handle and size
 * must match what was provided in the previous dma_map_page() call.
 * All other usages are undefined.
 *
 * After this call, reads by the CPU to the buffer are guaranteed to see
 * whatever the device wrote there.
 */
static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir,
		struct dma_attrs *attrs)
{
	if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
		__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
				      handle & ~PAGE_MASK, size, dir);
}

static void arm_dma_sync_single_for_cpu(struct device *dev,
		dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
	unsigned int offset = handle & (PAGE_SIZE - 1);
	struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
	__dma_page_dev_to_cpu(page, offset, size, dir);
}

static void arm_dma_sync_single_for_device(struct device *dev,
		dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
	unsigned int offset = handle & (PAGE_SIZE - 1);
	struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
	__dma_page_cpu_to_dev(page, offset, size, dir);
}

struct dma_map_ops arm_dma_ops = {
	.alloc			= arm_dma_alloc,
	.free			= arm_dma_free,
	.mmap			= arm_dma_mmap,
	.get_sgtable		= arm_dma_get_sgtable,
	.map_page		= arm_dma_map_page,
	.unmap_page		= arm_dma_unmap_page,
	.map_sg			= arm_dma_map_sg,
	.unmap_sg		= arm_dma_unmap_sg,
	.sync_single_for_cpu	= arm_dma_sync_single_for_cpu,
	.sync_single_for_device	= arm_dma_sync_single_for_device,
	.sync_sg_for_cpu	= arm_dma_sync_sg_for_cpu,
	.sync_sg_for_device	= arm_dma_sync_sg_for_device,
	.set_dma_mask		= arm_dma_set_mask,
};
EXPORT_SYMBOL(arm_dma_ops);

static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
	dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
				  dma_addr_t handle, struct dma_attrs *attrs);
static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
		 void *cpu_addr, dma_addr_t dma_addr, size_t size,
		 struct dma_attrs *attrs);

struct dma_map_ops arm_coherent_dma_ops = {
	.alloc			= arm_coherent_dma_alloc,
	.free			= arm_coherent_dma_free,
	.mmap			= arm_coherent_dma_mmap,
	.get_sgtable		= arm_dma_get_sgtable,
	.map_page		= arm_coherent_dma_map_page,
	.map_sg			= arm_dma_map_sg,
	.set_dma_mask		= arm_dma_set_mask,
};
EXPORT_SYMBOL(arm_coherent_dma_ops);

static int __dma_supported(struct device *dev, u64 mask, bool warn)
{
	unsigned long max_dma_pfn;

	/*
	 * If the mask allows for more memory than we can address,
	 * and we actually have that much memory, then we must
	 * indicate that DMA to this device is not supported.
	 */
	if (sizeof(mask) != sizeof(dma_addr_t) &&
	    mask > (dma_addr_t)~0 &&
	    dma_to_pfn(dev, ~0) < max_pfn - 1) {
		if (warn) {
			dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
				 mask);
			dev_warn(dev, "Driver did not use or check the return value from dma_set_coherent_mask()?\n");
		}
		return 0;
	}

	max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);

	/*
	 * Translate the device's DMA mask to a PFN limit.  This
	 * PFN number includes the page which we can DMA to.
	 */
	if (dma_to_pfn(dev, mask) < max_dma_pfn) {
		if (warn)
			dev_warn(dev, "Coherent DMA mask %#llx (pfn %#lx-%#lx) covers a smaller range of system memory than the DMA zone pfn 0x0-%#lx\n",
				 mask,
				 dma_to_pfn(dev, 0), dma_to_pfn(dev, mask) + 1,
				 max_dma_pfn + 1);
		return 0;
	}

	return 1;
}

static u64 get_coherent_dma_mask(struct device *dev)
{
	u64 mask = (u64)DMA_BIT_MASK(32);

	if (dev) {
		mask = dev->coherent_dma_mask;

		/*
		 * Sanity check the DMA mask - it must be non-zero, and
		 * must be able to be satisfied by a DMA allocation.
		 */
		if (mask == 0) {
			dev_warn(dev, "coherent DMA mask is unset\n");
			return 0;
		}

		if (!__dma_supported(dev, mask, true))
			return 0;
	}

	return mask;
}

static void __dma_clear_buffer(struct page *page, size_t size)
{
	/*
	 * Ensure that the allocated pages are zeroed, and that any data
	 * lurking in the kernel direct-mapped region is invalidated.
	 */
	if (PageHighMem(page)) {
		phys_addr_t base = __pfn_to_phys(page_to_pfn(page));
		phys_addr_t end = base + size;
		while (size > 0) {
			void *ptr = kmap_atomic(page);
			memset(ptr, 0, PAGE_SIZE);
			dmac_flush_range(ptr, ptr + PAGE_SIZE);
			kunmap_atomic(ptr);
			page++;
			size -= PAGE_SIZE;
		}
		outer_flush_range(base, end);
	} else {
		void *ptr = page_address(page);
		memset(ptr, 0, size);
		dmac_flush_range(ptr, ptr + size);
		outer_flush_range(__pa(ptr), __pa(ptr) + size);
	}
}

/*
 * Allocate a DMA buffer for 'dev' of size 'size' using the
 * specified gfp mask.  Note that 'size' must be page aligned.
 */
static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
{
	unsigned long order = get_order(size);
	struct page *page, *p, *e;

	page = alloc_pages(gfp, order);
	if (!page)
		return NULL;

	/*
	 * Now split the huge page and free the excess pages
	 */
	split_page(page, order);
	for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
		__free_page(p);

	__dma_clear_buffer(page, size);

	return page;
}

/*
 * Free a DMA buffer.  'size' must be page aligned.
 */
static void __dma_free_buffer(struct page *page, size_t size)
{
	struct page *e = page + (size >> PAGE_SHIFT);

	while (page < e) {
		__free_page(page);
		page++;
	}
}

#ifdef CONFIG_MMU

static void *__alloc_from_contiguous(struct device *dev, size_t size,
				     pgprot_t prot, struct page **ret_page,
				     const void *caller, bool want_vaddr);

static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
				 pgprot_t prot, struct page **ret_page,
				 const void *caller, bool want_vaddr);

static void *
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
	const void *caller)
{
	/*
	 * DMA allocation can be mapped to user space, so lets
	 * set VM_USERMAP flags too.
	 */
	return dma_common_contiguous_remap(page, size,
			VM_ARM_DMA_CONSISTENT | VM_USERMAP,
			prot, caller);
}

static void __dma_free_remap(void *cpu_addr, size_t size)
{
	dma_common_free_remap(cpu_addr, size,
			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
}

#define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_256K
static struct gen_pool *atomic_pool;

static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;

static int __init early_coherent_pool(char *p)
{
	atomic_pool_size = memparse(p, &p);
	return 0;
}
early_param("coherent_pool", early_coherent_pool);

void __init init_dma_coherent_pool_size(unsigned long size)
{
	/*
	 * Catch any attempt to set the pool size too late.
	 */
	BUG_ON(atomic_pool);

	/*
	 * Set architecture specific coherent pool size only if
	 * it has not been changed by kernel command line parameter.
	 */
	if (atomic_pool_size == DEFAULT_DMA_COHERENT_POOL_SIZE)
		atomic_pool_size = size;
}

/*
 * Initialise the coherent pool for atomic allocations.
 */
static int __init atomic_pool_init(void)
{
	pgprot_t prot = pgprot_dmacoherent(PAGE_KERNEL);
	gfp_t gfp = GFP_KERNEL | GFP_DMA;
	struct page *page;
	void *ptr;

	atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
	if (!atomic_pool)
		goto out;

	if (dev_get_cma_area(NULL))
		ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
					      &page, atomic_pool_init, true);
	else
		ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
					   &page, atomic_pool_init, true);
	if (ptr) {
		int ret;

		ret = gen_pool_add_virt(atomic_pool, (unsigned long)ptr,
					page_to_phys(page),
					atomic_pool_size, -1);
		if (ret)
			goto destroy_genpool;

		gen_pool_set_algo(atomic_pool,
				gen_pool_first_fit_order_align,
				(void *)PAGE_SHIFT);
		pr_info("DMA: preallocated %zd KiB pool for atomic coherent allocations\n",
		       atomic_pool_size / 1024);
		return 0;
	}

destroy_genpool:
	gen_pool_destroy(atomic_pool);
	atomic_pool = NULL;
out:
	pr_err("DMA: failed to allocate %zx KiB pool for atomic coherent allocation\n",
	       atomic_pool_size / 1024);
	return -ENOMEM;
}
/*
 * CMA is activated by core_initcall, so we must be called after it.
 */
postcore_initcall(atomic_pool_init);

struct dma_contig_early_reserve {
	phys_addr_t base;
	unsigned long size;
};

static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata;

static int dma_mmu_remap_num __initdata;

void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
{
	dma_mmu_remap[dma_mmu_remap_num].base = base;
	dma_mmu_remap[dma_mmu_remap_num].size = size;
	dma_mmu_remap_num++;
}

void __init dma_contiguous_remap(void)
{
	int i;
	for (i = 0; i < dma_mmu_remap_num; i++) {
		phys_addr_t start = dma_mmu_remap[i].base;
		phys_addr_t end = start + dma_mmu_remap[i].size;
		struct map_desc map;
		unsigned long addr;

		if (end > arm_lowmem_limit)
			end = arm_lowmem_limit;
		if (start >= end)
			continue;

		map.pfn = __phys_to_pfn(start);
		map.virtual = __phys_to_virt(start);
		map.length = end - start;
		map.type = MT_MEMORY_DMA_READY;

		/*
		 * Clear previous low-memory mapping to ensure that the
		 * TLB does not see any conflicting entries, then flush
		 * the TLB of the old entries before creating new mappings.
		 *
		 * This ensures that any speculatively loaded TLB entries
		 * (even though they may be rare) can not cause any problems,
		 * and ensures that this code is architecturally compliant.
		 */
		for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);
		     addr += PMD_SIZE)
			pmd_clear(pmd_off_k(addr));

		flush_tlb_kernel_range(__phys_to_virt(start),
				       __phys_to_virt(end));

		iotable_init(&map, 1);
	}
}

static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
			    void *data)
{
	struct page *page = virt_to_page(addr);
	pgprot_t prot = *(pgprot_t *)data;

	set_pte_ext(pte, mk_pte(page, prot), 0);
	return 0;
}

static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
{
	unsigned long start = (unsigned long) page_address(page);
	unsigned end = start + size;

	apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot);
	flush_tlb_kernel_range(start, end);
}

static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
				 pgprot_t prot, struct page **ret_page,
				 const void *caller, bool want_vaddr)
{
	struct page *page;
	void *ptr = NULL;
	page = __dma_alloc_buffer(dev, size, gfp);
	if (!page)
		return NULL;
	if (!want_vaddr)
		goto out;

	ptr = __dma_alloc_remap(page, size, gfp, prot, caller);
	if (!ptr) {
		__dma_free_buffer(page, size);
		return NULL;
	}

 out:
	*ret_page = page;
	return ptr;
}

static void *__alloc_from_pool(size_t size, struct page **ret_page)
{
	unsigned long val;
	void *ptr = NULL;

	if (!atomic_pool) {
		WARN(1, "coherent pool not initialised!\n");
		return NULL;
	}

	val = gen_pool_alloc(atomic_pool, size);
	if (val) {
		phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);

		*ret_page = phys_to_page(phys);
		ptr = (void *)val;
	}

	return ptr;
}

static bool __in_atomic_pool(void *start, size_t size)
{
	return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
}

static int __free_from_pool(void *start, size_t size)
{
	if (!__in_atomic_pool(start, size))
		return 0;

	gen_pool_free(atomic_pool, (unsigned long)start, size);

	return 1;
}

static void *__alloc_from_contiguous(struct device *dev, size_t size,
				     pgprot_t prot, struct page **ret_page,
				     const void *caller, bool want_vaddr)
{
	unsigned long order = get_order(size);
	size_t count = size >> PAGE_SHIFT;
	struct page *page;
	void *ptr = NULL;

	page = dma_alloc_from_contiguous(dev, count, order);
	if (!page)
		return NULL;

	__dma_clear_buffer(page, size);

	if (!want_vaddr)
		goto out;

	if (PageHighMem(page)) {
		ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
		if (!ptr) {
			dma_release_from_contiguous(dev, page, count);
			return NULL;
		}
	} else {
		__dma_remap(page, size, prot);
		ptr = page_address(page);
	}

 out:
	*ret_page = page;
	return ptr;
}

static void __free_from_contiguous(struct device *dev, struct page *page,
				   void *cpu_addr, size_t size, bool want_vaddr)
{
	if (want_vaddr) {
		if (PageHighMem(page))
			__dma_free_remap(cpu_addr, size);
		else
			__dma_remap(page, size, PAGE_KERNEL);
	}
	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}

static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
{
	prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
			    pgprot_writecombine(prot) :
			    pgprot_dmacoherent(prot);
	return prot;
}

#define nommu() 0

#else	/* !CONFIG_MMU */

#define nommu() 1

#define __get_dma_pgprot(attrs, prot)				__pgprot(0)
#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv)	NULL
#define __alloc_from_pool(size, ret_page)			NULL
#define __alloc_from_contiguous(dev, size, prot, ret, c, wv)	NULL
#define __free_from_pool(cpu_addr, size)			0
#define __free_from_contiguous(dev, page, cpu_addr, size, wv)	do { } while (0)
#define __dma_free_remap(cpu_addr, size)			do { } while (0)

#endif	/* CONFIG_MMU */

static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp,
				   struct page **ret_page)
{
	struct page *page;
	page = __dma_alloc_buffer(dev, size, gfp);
	if (!page)
		return NULL;

	*ret_page = page;
	return page_address(page);
}

static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
			 gfp_t gfp, pgprot_t prot, bool is_coherent,
			 struct dma_attrs *attrs, const void *caller)
{
	u64 mask = get_coherent_dma_mask(dev);
	struct page *page = NULL;
	void *addr;
	bool want_vaddr;

#ifdef CONFIG_DMA_API_DEBUG
	u64 limit = (mask + 1) & ~mask;
	if (limit && size >= limit) {
		dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n",
			size, mask);
		return NULL;
	}
#endif

	if (!mask)
		return NULL;

	if (mask < 0xffffffffULL)
		gfp |= GFP_DMA;

	/*
	 * Following is a work-around (a.k.a. hack) to prevent pages
	 * with __GFP_COMP being passed to split_page() which cannot
	 * handle them.  The real problem is that this flag probably
	 * should be 0 on ARM as it is not supported on this
	 * platform; see CONFIG_HUGETLBFS.
	 */
	gfp &= ~(__GFP_COMP);

	*handle = DMA_ERROR_CODE;
	size = PAGE_ALIGN(size);
	want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs);

	if (nommu())
		addr = __alloc_simple_buffer(dev, size, gfp, &page);
	else if (dev_get_cma_area(dev) && (gfp & __GFP_DIRECT_RECLAIM))
		addr = __alloc_from_contiguous(dev, size, prot, &page,
					       caller, want_vaddr);
	else if (is_coherent)
		addr = __alloc_simple_buffer(dev, size, gfp, &page);
	else if (!gfpflags_allow_blocking(gfp))
		addr = __alloc_from_pool(size, &page);
	else
		addr = __alloc_remap_buffer(dev, size, gfp, prot, &page,
					    caller, want_vaddr);

	if (page)
		*handle = pfn_to_dma(dev, page_to_pfn(page));

	return want_vaddr ? addr : page;
}

/*
 * Allocate DMA-coherent memory space and return both the kernel remapped
 * virtual and bus address for that space.
 */
void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
		    gfp_t gfp, struct dma_attrs *attrs)
{
	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);

	return __dma_alloc(dev, size, handle, gfp, prot, false,
			   attrs, __builtin_return_address(0));
}

static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
	dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
{
	return __dma_alloc(dev, size, handle, gfp, PAGE_KERNEL, true,
			   attrs, __builtin_return_address(0));
}

static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
		 void *cpu_addr, dma_addr_t dma_addr, size_t size,
		 struct dma_attrs *attrs)
{
	int ret = -ENXIO;
#ifdef CONFIG_MMU
	unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
	unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
	unsigned long pfn = dma_to_pfn(dev, dma_addr);
	unsigned long off = vma->vm_pgoff;

	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
		return ret;

	if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
		ret = remap_pfn_range(vma, vma->vm_start,
				      pfn + off,
				      vma->vm_end - vma->vm_start,
				      vma->vm_page_prot);
	}
#endif	/* CONFIG_MMU */

	return ret;
}

/*
 * Create userspace mapping for the DMA-coherent memory.
 */
static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
		 void *cpu_addr, dma_addr_t dma_addr, size_t size,
		 struct dma_attrs *attrs)
{
	return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}

int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
		 void *cpu_addr, dma_addr_t dma_addr, size_t size,
		 struct dma_attrs *attrs)
{
#ifdef CONFIG_MMU
	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
#endif	/* CONFIG_MMU */
	return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}

/*
 * Free a buffer as defined by the above mapping.
 */
static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
			   dma_addr_t handle, struct dma_attrs *attrs,
			   bool is_coherent)
{
	struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
	bool want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs);

	size = PAGE_ALIGN(size);

	if (nommu()) {
		__dma_free_buffer(page, size);
	} else if (!is_coherent && __free_from_pool(cpu_addr, size)) {
		return;
	} else if (!dev_get_cma_area(dev)) {
		if (want_vaddr && !is_coherent)
			__dma_free_remap(cpu_addr, size);
		__dma_free_buffer(page, size);
	} else {
		/*
		 * Non-atomic allocations cannot be freed with IRQs disabled
		 */
		WARN_ON(irqs_disabled());
		__free_from_contiguous(dev, page, cpu_addr, size, want_vaddr);
	}
}

void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
		  dma_addr_t handle, struct dma_attrs *attrs)
{
	__arm_dma_free(dev, size, cpu_addr, handle, attrs, false);
}

static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
				  dma_addr_t handle, struct dma_attrs *attrs)
{
	__arm_dma_free(dev, size, cpu_addr, handle, attrs, true);
}

int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
		 void *cpu_addr, dma_addr_t handle, size_t size,
		 struct dma_attrs *attrs)
{
	struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
	int ret;

	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
	if (unlikely(ret))
		return ret;

	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
	return 0;
}

static void dma_cache_maint_page(struct page *page, unsigned long offset,
	size_t size, enum dma_data_direction dir,
	void (*op)(const void *, size_t, int))
{
	unsigned long pfn;
	size_t left = size;

	pfn = page_to_pfn(page) + offset / PAGE_SIZE;
	offset %= PAGE_SIZE;

	/*
	 * A single sg entry may refer to multiple physically contiguous
	 * pages.  But we still need to process highmem pages individually.
	 * If highmem is not configured then the bulk of this loop gets
	 * optimized out.
	 */
	do {
		size_t len = left;
		void *vaddr;

		page = pfn_to_page(pfn);

		if (PageHighMem(page)) {
			if (len + offset > PAGE_SIZE)
				len = PAGE_SIZE - offset;

			if (cache_is_vipt_nonaliasing()) {
				vaddr = kmap_atomic(page);
				op(vaddr + offset, len, dir);
				kunmap_atomic(vaddr);
			} else {
				vaddr = kmap_high_get(page);
				if (vaddr) {
					op(vaddr + offset, len, dir);
					kunmap_high(page);
				}
			}
		} else {
			vaddr = page_address(page) + offset;
			op(vaddr, len, dir);
		}
		offset = 0;
		pfn++;
		left -= len;
	} while (left);
}

/*
 * Make an area consistent for devices.
 * Note: Drivers should NOT use this function directly, as it will break
 * platforms with CONFIG_DMABOUNCE.
 * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
 */
static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
	size_t size, enum dma_data_direction dir)
{
	phys_addr_t paddr;

	dma_cache_maint_page(page, off, size, dir, dmac_map_area);

	paddr = page_to_phys(page) + off;
	if (dir == DMA_FROM_DEVICE) {
		outer_inv_range(paddr, paddr + size);
	} else {
		outer_clean_range(paddr, paddr + size);
	}
	/* FIXME: non-speculating: flush on bidirectional mappings? */
}

static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
	size_t size, enum dma_data_direction dir)
{
	phys_addr_t paddr = page_to_phys(page) + off;

	/* FIXME: non-speculating: not required */
	/* in any case, don't bother invalidating if DMA to device */
	if (dir != DMA_TO_DEVICE) {
		outer_inv_range(paddr, paddr + size);

		dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
	}

	/*
	 * Mark the D-cache clean for these pages to avoid extra flushing.
	 */
	if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
		unsigned long pfn;
		size_t left = size;

		pfn = page_to_pfn(page) + off / PAGE_SIZE;
		off %= PAGE_SIZE;
		if (off) {
			pfn++;
			left -= PAGE_SIZE - off;
		}
		while (left >= PAGE_SIZE) {
			page = pfn_to_page(pfn++);
			set_bit(PG_dcache_clean, &page->flags);
			left -= PAGE_SIZE;
		}
	}
}

/**
 * arm_dma_map_sg - map a set of SG buffers for streaming mode DMA
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @sg: list of buffers
 * @nents: number of buffers to map
 * @dir: DMA transfer direction
 *
 * Map a set of buffers described by scatterlist in streaming mode for DMA.
 * This is the scatter-gather version of the dma_map_single interface.
 * Here the scatter gather list elements are each tagged with the
 * appropriate dma address and length.  They are obtained via
 * sg_dma_{address,length}.
 *
 * Device ownership issues as mentioned for dma_map_single are the same
 * here.
 */
int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
		enum dma_data_direction dir, struct dma_attrs *attrs)
{
	struct dma_map_ops *ops = get_dma_ops(dev);
	struct scatterlist *s;
	int i, j;

	for_each_sg(sg, s, nents, i) {
#ifdef CONFIG_NEED_SG_DMA_LENGTH
		s->dma_length = s->length;
#endif
		s->dma_address = ops->map_page(dev, sg_page(s), s->offset,
						s->length, dir, attrs);
		if (dma_mapping_error(dev, s->dma_address))
			goto bad_mapping;
	}
	return nents;

 bad_mapping:
	for_each_sg(sg, s, i, j)
		ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
	return 0;
}

/**
 * arm_dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @sg: list of buffers
 * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 *
 * Unmap a set of streaming mode DMA translations.  Again, CPU access
 * rules concerning calls here are the same as for dma_unmap_single().
 */
void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
		enum dma_data_direction dir, struct dma_attrs *attrs)
{
	struct dma_map_ops *ops = get_dma_ops(dev);
	struct scatterlist *s;

	int i;

	for_each_sg(sg, s, nents, i)
		ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
}

/**
 * arm_dma_sync_sg_for_cpu
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @sg: list of buffers
 * @nents: number of buffers to map (returned from dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 */
void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
			int nents, enum dma_data_direction dir)
{
	struct dma_map_ops *ops = get_dma_ops(dev);
	struct scatterlist *s;
	int i;

	for_each_sg(sg, s, nents, i)
		ops->sync_single_for_cpu(dev, sg_dma_address(s), s->length,
					 dir);
}

/**
 * arm_dma_sync_sg_for_device
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
 * @sg: list of buffers
 * @nents: number of buffers to map (returned from dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 */
void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
			int nents, enum dma_data_direction dir)
{
	struct dma_map_ops *ops = get_dma_ops(dev);
	struct scatterlist *s;
	int i;

	for_each_sg(sg, s, nents, i)
		ops->sync_single_for_device(dev, sg_dma_address(s), s->length,
					    dir);
}

/*
 * Return whether the given device DMA address mask can be supported
 * properly.  For example, if your device can only drive the low 24-bits
 * during bus mastering, then you would pass 0x00ffffff as the mask
 * to this function.
 */
int dma_supported(struct device *dev, u64 mask)
{
	return __dma_supported(dev, mask, false);
}
EXPORT_SYMBOL(dma_supported);

int arm_dma_set_mask(struct device *dev, u64 dma_mask)
{
	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
		return -EIO;

	*dev->dma_mask = dma_mask;

	return 0;
}

#define PREALLOC_DMA_DEBUG_ENTRIES	4096

static int __init dma_debug_do_init(void)
{
	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
	return 0;
}
fs_initcall(dma_debug_do_init);

#ifdef CONFIG_ARM_DMA_USE_IOMMU

/* IOMMU */

static int extend_iommu_mapping(struct dma_iommu_mapping *mapping);

static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
				      size_t size)
{
	unsigned int order = get_order(size);
	unsigned int align = 0;
	unsigned int count, start;
	size_t mapping_size = mapping->bits << PAGE_SHIFT;
	unsigned long flags;
	dma_addr_t iova;
	int i;

	if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT)
		order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT;

	count = PAGE_ALIGN(size) >> PAGE_SHIFT;
	align = (1 << order) - 1;

	spin_lock_irqsave(&mapping->lock, flags);
	for (i = 0; i < mapping->nr_bitmaps; i++) {
		start = bitmap_find_next_zero_area(mapping->bitmaps[i],
				mapping->bits, 0, count, align);

		if (start > mapping->bits)
			continue;

		bitmap_set(mapping->bitmaps[i], start, count);
		break;
	}

	/*
	 * No unused range found. Try to extend the existing mapping
	 * and perform a second attempt to reserve an IO virtual
	 * address range of size bytes.
	 */
	if (i == mapping->nr_bitmaps) {
		if (extend_iommu_mapping(mapping)) {
			spin_unlock_irqrestore(&mapping->lock, flags);
			return DMA_ERROR_CODE;
		}

		start = bitmap_find_next_zero_area(mapping->bitmaps[i],
				mapping->bits, 0, count, align);

		if (start > mapping->bits) {
			spin_unlock_irqrestore(&mapping->lock, flags);
			return DMA_ERROR_CODE;
		}

		bitmap_set(mapping->bitmaps[i], start, count);
	}
	spin_unlock_irqrestore(&mapping->lock, flags);

	iova = mapping->base + (mapping_size * i);
	iova += start << PAGE_SHIFT;

	return iova;
}

static inline void __free_iova(struct dma_iommu_mapping *mapping,
			       dma_addr_t addr, size_t size)
{
	unsigned int start, count;
	size_t mapping_size = mapping->bits << PAGE_SHIFT;
	unsigned long flags;
	dma_addr_t bitmap_base;
	u32 bitmap_index;

	if (!size)
		return;

	bitmap_index = (u32) (addr - mapping->base) / (u32) mapping_size;
	BUG_ON(addr < mapping->base || bitmap_index > mapping->extensions);

	bitmap_base = mapping->base + mapping_size * bitmap_index;

	start = (addr - bitmap_base) >>	PAGE_SHIFT;

	if (addr + size > bitmap_base + mapping_size) {
		/*
		 * The address range to be freed reaches into the iova
		 * range of the next bitmap. This should not happen as
		 * we don't allow this in __alloc_iova (at the
		 * moment).
		 */
		BUG();
	} else
		count = size >> PAGE_SHIFT;

	spin_lock_irqsave(&mapping->lock, flags);
	bitmap_clear(mapping->bitmaps[bitmap_index], start, count);
	spin_unlock_irqrestore(&mapping->lock, flags);
}

static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
					  gfp_t gfp, struct dma_attrs *attrs)
{
	struct page **pages;
	int count = size >> PAGE_SHIFT;
	int array_size = count * sizeof(struct page *);
	int i = 0;

	if (array_size <= PAGE_SIZE)
		pages = kzalloc(array_size, GFP_KERNEL);
	else
		pages = vzalloc(array_size);
	if (!pages)
		return NULL;

	if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs))
	{
		unsigned long order = get_order(size);
		struct page *page;

		page = dma_alloc_from_contiguous(dev, count, order);
		if (!page)
			goto error;

		__dma_clear_buffer(page, size);

		for (i = 0; i < count; i++)
			pages[i] = page + i;

		return pages;
	}

	/*
	 * IOMMU can map any pages, so himem can also be used here
	 */
	gfp |= __GFP_NOWARN | __GFP_HIGHMEM;

	while (count) {
		int j, order;

		for (order = __fls(count); order > 0; --order) {
			/*
			 * We do not want OOM killer to be invoked as long
			 * as we can fall back to single pages, so we force
			 * __GFP_NORETRY for orders higher than zero.
			 */
			pages[i] = alloc_pages(gfp | __GFP_NORETRY, order);
			if (pages[i])
				break;
		}

		if (!pages[i]) {
			/*
			 * Fall back to single page allocation.
			 * Might invoke OOM killer as last resort.
			 */
			pages[i] = alloc_pages(gfp, 0);
			if (!pages[i])
				goto error;
		}

		if (order) {
			split_page(pages[i], order);
			j = 1 << order;
			while (--j)
				pages[i + j] = pages[i] + j;
		}

		__dma_clear_buffer(pages[i], PAGE_SIZE << order);
		i += 1 << order;
		count -= 1 << order;
	}

	return pages;
error:
	while (i--)
		if (pages[i])
			__free_pages(pages[i], 0);
	if (array_size <= PAGE_SIZE)
		kfree(pages);
	else
		vfree(pages);
	return NULL;
}

static int __iommu_free_buffer(struct device *dev, struct page **pages,
			       size_t size, struct dma_attrs *attrs)
{
	int count = size >> PAGE_SHIFT;
	int array_size = count * sizeof(struct page *);
	int i;

	if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
		dma_release_from_contiguous(dev, pages[0], count);
	} else {
		for (i = 0; i < count; i++)
			if (pages[i])
				__free_pages(pages[i], 0);
	}

	if (array_size <= PAGE_SIZE)
		kfree(pages);
	else
		vfree(pages);
	return 0;
}

/*
 * Create a CPU mapping for a specified pages
 */
static void *
__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
		    const void *caller)
{
	return dma_common_pages_remap(pages, size,
			VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
}

/*
 * Create a mapping in device IO address space for specified pages
 */
static dma_addr_t
__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
	dma_addr_t dma_addr, iova;
	int i;

	dma_addr = __alloc_iova(mapping, size);
	if (dma_addr == DMA_ERROR_CODE)
		return dma_addr;

	iova = dma_addr;
	for (i = 0; i < count; ) {
		int ret;

		unsigned int next_pfn = page_to_pfn(pages[i]) + 1;
		phys_addr_t phys = page_to_phys(pages[i]);
		unsigned int len, j;

		for (j = i + 1; j < count; j++, next_pfn++)
			if (page_to_pfn(pages[j]) != next_pfn)
				break;

		len = (j - i) << PAGE_SHIFT;
		ret = iommu_map(mapping->domain, iova, phys, len,
				IOMMU_READ|IOMMU_WRITE);
		if (ret < 0)
			goto fail;
		iova += len;
		i = j;
	}
	return dma_addr;
fail:
	iommu_unmap(mapping->domain, dma_addr, iova-dma_addr);
	__free_iova(mapping, dma_addr, size);
	return DMA_ERROR_CODE;
}

static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);

	/*
	 * add optional in-page offset from iova to size and align
	 * result to page size
	 */
	size = PAGE_ALIGN((iova & ~PAGE_MASK) + size);
	iova &= PAGE_MASK;

	iommu_unmap(mapping->domain, iova, size);
	__free_iova(mapping, iova, size);
	return 0;
}

static struct page **__atomic_get_pages(void *addr)
{
	struct page *page;
	phys_addr_t phys;

	phys = gen_pool_virt_to_phys(atomic_pool, (unsigned long)addr);
	page = phys_to_page(phys);

	return (struct page **)page;
}

static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
{
	struct vm_struct *area;

	if (__in_atomic_pool(cpu_addr, PAGE_SIZE))
		return __atomic_get_pages(cpu_addr);

	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
		return cpu_addr;

	area = find_vm_area(cpu_addr);
	if (area && (area->flags & VM_ARM_DMA_CONSISTENT))
		return area->pages;
	return NULL;
}

static void *__iommu_alloc_atomic(struct device *dev, size_t size,
				  dma_addr_t *handle)
{
	struct page *page;
	void *addr;

	addr = __alloc_from_pool(size, &page);
	if (!addr)
		return NULL;

	*handle = __iommu_create_mapping(dev, &page, size);
	if (*handle == DMA_ERROR_CODE)
		goto err_mapping;

	return addr;

err_mapping:
	__free_from_pool(addr, size);
	return NULL;
}

static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
				dma_addr_t handle, size_t size)
{
	__iommu_remove_mapping(dev, handle, size);
	__free_from_pool(cpu_addr, size);
}

static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
	    dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
{
	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
	struct page **pages;
	void *addr = NULL;

	*handle = DMA_ERROR_CODE;
	size = PAGE_ALIGN(size);

	if (!gfpflags_allow_blocking(gfp))
		return __iommu_alloc_atomic(dev, size, handle);

	/*
	 * Following is a work-around (a.k.a. hack) to prevent pages
	 * with __GFP_COMP being passed to split_page() which cannot
	 * handle them.  The real problem is that this flag probably
	 * should be 0 on ARM as it is not supported on this
	 * platform; see CONFIG_HUGETLBFS.
	 */
	gfp &= ~(__GFP_COMP);

	pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
	if (!pages)
		return NULL;

	*handle = __iommu_create_mapping(dev, pages, size);
	if (*handle == DMA_ERROR_CODE)
		goto err_buffer;

	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
		return pages;

	addr = __iommu_alloc_remap(pages, size, gfp, prot,
				   __builtin_return_address(0));
	if (!addr)
		goto err_mapping;

	return addr;

err_mapping:
	__iommu_remove_mapping(dev, *handle, size);
err_buffer:
	__iommu_free_buffer(dev, pages, size, attrs);
	return NULL;
}

static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
		    void *cpu_addr, dma_addr_t dma_addr, size_t size,
		    struct dma_attrs *attrs)
{
	unsigned long uaddr = vma->vm_start;
	unsigned long usize = vma->vm_end - vma->vm_start;
	struct page **pages = __iommu_get_pages(cpu_addr, attrs);
	unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
	unsigned long off = vma->vm_pgoff;

	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);

	if (!pages)
		return -ENXIO;

	if (off >= nr_pages || (usize >> PAGE_SHIFT) > nr_pages - off)
		return -ENXIO;

	pages += off;

	do {
		int ret = vm_insert_page(vma, uaddr, *pages++);
		if (ret) {
			pr_err("Remapping memory failed: %d\n", ret);
			return ret;
		}
		uaddr += PAGE_SIZE;
		usize -= PAGE_SIZE;
	} while (usize > 0);

	return 0;
}

/*
 * free a page as defined by the above mapping.
 * Must not be called with IRQs disabled.
 */
void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
			  dma_addr_t handle, struct dma_attrs *attrs)
{
	struct page **pages;
	size = PAGE_ALIGN(size);

	if (__in_atomic_pool(cpu_addr, size)) {
		__iommu_free_atomic(dev, cpu_addr, handle, size);
		return;
	}

	pages = __iommu_get_pages(cpu_addr, attrs);
	if (!pages) {
		WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
		return;
	}

	if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
		dma_common_free_remap(cpu_addr, size,
			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
	}

	__iommu_remove_mapping(dev, handle, size);
	__iommu_free_buffer(dev, pages, size, attrs);
}

static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
				 void *cpu_addr, dma_addr_t dma_addr,
				 size_t size, struct dma_attrs *attrs)
{
	unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
	struct page **pages = __iommu_get_pages(cpu_addr, attrs);

	if (!pages)
		return -ENXIO;

	return sg_alloc_table_from_pages(sgt, pages, count, 0, size,
					 GFP_KERNEL);
}

static int __dma_direction_to_prot(enum dma_data_direction dir)
{
	int prot;

	switch (dir) {
	case DMA_BIDIRECTIONAL:
		prot = IOMMU_READ | IOMMU_WRITE;
		break;
	case DMA_TO_DEVICE:
		prot = IOMMU_READ;
		break;
	case DMA_FROM_DEVICE:
		prot = IOMMU_WRITE;
		break;
	default:
		prot = 0;
	}

	return prot;
}

/*
 * Map a part of the scatter-gather list into contiguous io address space
 */
static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
			  size_t size, dma_addr_t *handle,
			  enum dma_data_direction dir, struct dma_attrs *attrs,
			  bool is_coherent)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t iova, iova_base;
	int ret = 0;
	unsigned int count;
	struct scatterlist *s;
	int prot;

	size = PAGE_ALIGN(size);
	*handle = DMA_ERROR_CODE;

	iova_base = iova = __alloc_iova(mapping, size);
	if (iova == DMA_ERROR_CODE)
		return -ENOMEM;

	for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
		phys_addr_t phys = page_to_phys(sg_page(s));
		unsigned int len = PAGE_ALIGN(s->offset + s->length);

		if (!is_coherent &&
			!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
			__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);

		prot = __dma_direction_to_prot(dir);

		ret = iommu_map(mapping->domain, iova, phys, len, prot);
		if (ret < 0)
			goto fail;
		count += len >> PAGE_SHIFT;
		iova += len;
	}
	*handle = iova_base;

	return 0;
fail:
	iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
	__free_iova(mapping, iova_base, size);
	return ret;
}

static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
		     enum dma_data_direction dir, struct dma_attrs *attrs,
		     bool is_coherent)
{
	struct scatterlist *s = sg, *dma = sg, *start = sg;
	int i, count = 0;
	unsigned int offset = s->offset;
	unsigned int size = s->offset + s->length;
	unsigned int max = dma_get_max_seg_size(dev);

	for (i = 1; i < nents; i++) {
		s = sg_next(s);

		s->dma_address = DMA_ERROR_CODE;
		s->dma_length = 0;

		if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
			if (__map_sg_chunk(dev, start, size, &dma->dma_address,
			    dir, attrs, is_coherent) < 0)
				goto bad_mapping;

			dma->dma_address += offset;
			dma->dma_length = size - offset;

			size = offset = s->offset;
			start = s;
			dma = sg_next(dma);
			count += 1;
		}
		size += s->length;
	}
	if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs,
		is_coherent) < 0)
		goto bad_mapping;

	dma->dma_address += offset;
	dma->dma_length = size - offset;

	return count+1;

bad_mapping:
	for_each_sg(sg, s, count, i)
		__iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
	return 0;
}

/**
 * arm_coherent_iommu_map_sg - map a set of SG buffers for streaming mode DMA
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to map
 * @dir: DMA transfer direction
 *
 * Map a set of i/o coherent buffers described by scatterlist in streaming
 * mode for DMA. The scatter gather list elements are merged together (if
 * possible) and tagged with the appropriate dma address and length. They are
 * obtained via sg_dma_{address,length}.
 */
int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
		int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
{
	return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
}

/**
 * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to map
 * @dir: DMA transfer direction
 *
 * Map a set of buffers described by scatterlist in streaming mode for DMA.
 * The scatter gather list elements are merged together (if possible) and
 * tagged with the appropriate dma address and length. They are obtained via
 * sg_dma_{address,length}.
 */
int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
		int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
{
	return __iommu_map_sg(dev, sg, nents, dir, attrs, false);
}

static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
		int nents, enum dma_data_direction dir, struct dma_attrs *attrs,
		bool is_coherent)
{
	struct scatterlist *s;
	int i;

	for_each_sg(sg, s, nents, i) {
		if (sg_dma_len(s))
			__iommu_remove_mapping(dev, sg_dma_address(s),
					       sg_dma_len(s));
		if (!is_coherent &&
		    !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
			__dma_page_dev_to_cpu(sg_page(s), s->offset,
					      s->length, dir);
	}
}

/**
 * arm_coherent_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 *
 * Unmap a set of streaming mode DMA translations.  Again, CPU access
 * rules concerning calls here are the same as for dma_unmap_single().
 */
void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
		int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
{
	__iommu_unmap_sg(dev, sg, nents, dir, attrs, true);
}

/**
 * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 *
 * Unmap a set of streaming mode DMA translations.  Again, CPU access
 * rules concerning calls here are the same as for dma_unmap_single().
 */
void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
			enum dma_data_direction dir, struct dma_attrs *attrs)
{
	__iommu_unmap_sg(dev, sg, nents, dir, attrs, false);
}

/**
 * arm_iommu_sync_sg_for_cpu
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to map (returned from dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 */
void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
			int nents, enum dma_data_direction dir)
{
	struct scatterlist *s;
	int i;

	for_each_sg(sg, s, nents, i)
		__dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);

}

/**
 * arm_iommu_sync_sg_for_device
 * @dev: valid struct device pointer
 * @sg: list of buffers
 * @nents: number of buffers to map (returned from dma_map_sg)
 * @dir: DMA transfer direction (same as was passed to dma_map_sg)
 */
void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
			int nents, enum dma_data_direction dir)
{
	struct scatterlist *s;
	int i;

	for_each_sg(sg, s, nents, i)
		__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
}

/**
 * arm_coherent_iommu_map_page
 * @dev: valid struct device pointer
 * @page: page that buffer resides in
 * @offset: offset into page for start of buffer
 * @size: size of buffer to map
 * @dir: DMA transfer direction
 *
 * Coherent IOMMU aware version of arm_dma_map_page()
 */
static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *page,
	     unsigned long offset, size_t size, enum dma_data_direction dir,
	     struct dma_attrs *attrs)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t dma_addr;
	int ret, prot, len = PAGE_ALIGN(size + offset);

	dma_addr = __alloc_iova(mapping, len);
	if (dma_addr == DMA_ERROR_CODE)
		return dma_addr;

	prot = __dma_direction_to_prot(dir);

	ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
	if (ret < 0)
		goto fail;

	return dma_addr + offset;
fail:
	__free_iova(mapping, dma_addr, len);
	return DMA_ERROR_CODE;
}

/**
 * arm_iommu_map_page
 * @dev: valid struct device pointer
 * @page: page that buffer resides in
 * @offset: offset into page for start of buffer
 * @size: size of buffer to map
 * @dir: DMA transfer direction
 *
 * IOMMU aware version of arm_dma_map_page()
 */
static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
	     unsigned long offset, size_t size, enum dma_data_direction dir,
	     struct dma_attrs *attrs)
{
	if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
		__dma_page_cpu_to_dev(page, offset, size, dir);

	return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
}

/**
 * arm_coherent_iommu_unmap_page
 * @dev: valid struct device pointer
 * @handle: DMA address of buffer
 * @size: size of buffer (same as passed to dma_map_page)
 * @dir: DMA transfer direction (same as passed to dma_map_page)
 *
 * Coherent IOMMU aware version of arm_dma_unmap_page()
 */
static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir,
		struct dma_attrs *attrs)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t iova = handle & PAGE_MASK;
	int offset = handle & ~PAGE_MASK;
	int len = PAGE_ALIGN(size + offset);

	if (!iova)
		return;

	iommu_unmap(mapping->domain, iova, len);
	__free_iova(mapping, iova, len);
}

/**
 * arm_iommu_unmap_page
 * @dev: valid struct device pointer
 * @handle: DMA address of buffer
 * @size: size of buffer (same as passed to dma_map_page)
 * @dir: DMA transfer direction (same as passed to dma_map_page)
 *
 * IOMMU aware version of arm_dma_unmap_page()
 */
static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir,
		struct dma_attrs *attrs)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t iova = handle & PAGE_MASK;
	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
	int offset = handle & ~PAGE_MASK;
	int len = PAGE_ALIGN(size + offset);

	if (!iova)
		return;

	if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
		__dma_page_dev_to_cpu(page, offset, size, dir);

	iommu_unmap(mapping->domain, iova, len);
	__free_iova(mapping, iova, len);
}

static void arm_iommu_sync_single_for_cpu(struct device *dev,
		dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t iova = handle & PAGE_MASK;
	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
	unsigned int offset = handle & ~PAGE_MASK;

	if (!iova)
		return;

	__dma_page_dev_to_cpu(page, offset, size, dir);
}

static void arm_iommu_sync_single_for_device(struct device *dev,
		dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
	dma_addr_t iova = handle & PAGE_MASK;
	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
	unsigned int offset = handle & ~PAGE_MASK;

	if (!iova)
		return;

	__dma_page_cpu_to_dev(page, offset, size, dir);
}

struct dma_map_ops iommu_ops = {
	.alloc		= arm_iommu_alloc_attrs,
	.free		= arm_iommu_free_attrs,
	.mmap		= arm_iommu_mmap_attrs,
	.get_sgtable	= arm_iommu_get_sgtable,

	.map_page		= arm_iommu_map_page,
	.unmap_page		= arm_iommu_unmap_page,
	.sync_single_for_cpu	= arm_iommu_sync_single_for_cpu,
	.sync_single_for_device	= arm_iommu_sync_single_for_device,

	.map_sg			= arm_iommu_map_sg,
	.unmap_sg		= arm_iommu_unmap_sg,
	.sync_sg_for_cpu	= arm_iommu_sync_sg_for_cpu,
	.sync_sg_for_device	= arm_iommu_sync_sg_for_device,

	.set_dma_mask		= arm_dma_set_mask,
};

struct dma_map_ops iommu_coherent_ops = {
	.alloc		= arm_iommu_alloc_attrs,
	.free		= arm_iommu_free_attrs,
	.mmap		= arm_iommu_mmap_attrs,
	.get_sgtable	= arm_iommu_get_sgtable,

	.map_page	= arm_coherent_iommu_map_page,
	.unmap_page	= arm_coherent_iommu_unmap_page,

	.map_sg		= arm_coherent_iommu_map_sg,
	.unmap_sg	= arm_coherent_iommu_unmap_sg,

	.set_dma_mask	= arm_dma_set_mask,
};

/**
 * arm_iommu_create_mapping
 * @bus: pointer to the bus holding the client device (for IOMMU calls)
 * @base: start address of the valid IO address space
 * @size: maximum size of the valid IO address space
 *
 * Creates a mapping structure which holds information about used/unused
 * IO address ranges, which is required to perform memory allocation and
 * mapping with IOMMU aware functions.
 *
 * The client device need to be attached to the mapping with
 * arm_iommu_attach_device function.
 */
struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size)
{
	unsigned int bits = size >> PAGE_SHIFT;
	unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
	struct dma_iommu_mapping *mapping;
	int extensions = 1;
	int err = -ENOMEM;

	/* currently only 32-bit DMA address space is supported */
	if (size > DMA_BIT_MASK(32) + 1)
		return ERR_PTR(-ERANGE);

	if (!bitmap_size)
		return ERR_PTR(-EINVAL);

	if (bitmap_size > PAGE_SIZE) {
		extensions = bitmap_size / PAGE_SIZE;
		bitmap_size = PAGE_SIZE;
	}

	mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
	if (!mapping)
		goto err;

	mapping->bitmap_size = bitmap_size;
	mapping->bitmaps = kzalloc(extensions * sizeof(unsigned long *),
				GFP_KERNEL);
	if (!mapping->bitmaps)
		goto err2;

	mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL);
	if (!mapping->bitmaps[0])
		goto err3;

	mapping->nr_bitmaps = 1;
	mapping->extensions = extensions;
	mapping->base = base;
	mapping->bits = BITS_PER_BYTE * bitmap_size;

	spin_lock_init(&mapping->lock);

	mapping->domain = iommu_domain_alloc(bus);
	if (!mapping->domain)
		goto err4;

	kref_init(&mapping->kref);
	return mapping;
err4:
	kfree(mapping->bitmaps[0]);
err3:
	kfree(mapping->bitmaps);
err2:
	kfree(mapping);
err:
	return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(arm_iommu_create_mapping);

static void release_iommu_mapping(struct kref *kref)
{
	int i;
	struct dma_iommu_mapping *mapping =
		container_of(kref, struct dma_iommu_mapping, kref);

	iommu_domain_free(mapping->domain);
	for (i = 0; i < mapping->nr_bitmaps; i++)
		kfree(mapping->bitmaps[i]);
	kfree(mapping->bitmaps);
	kfree(mapping);
}

static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
{
	int next_bitmap;

	if (mapping->nr_bitmaps >= mapping->extensions)
		return -EINVAL;

	next_bitmap = mapping->nr_bitmaps;
	mapping->bitmaps[next_bitmap] = kzalloc(mapping->bitmap_size,
						GFP_ATOMIC);
	if (!mapping->bitmaps[next_bitmap])
		return -ENOMEM;

	mapping->nr_bitmaps++;

	return 0;
}

void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
	if (mapping)
		kref_put(&mapping->kref, release_iommu_mapping);
}
EXPORT_SYMBOL_GPL(arm_iommu_release_mapping);

static int __arm_iommu_attach_device(struct device *dev,
				     struct dma_iommu_mapping *mapping)
{
	int err;

	err = iommu_attach_device(mapping->domain, dev);
	if (err)
		return err;

	kref_get(&mapping->kref);
	to_dma_iommu_mapping(dev) = mapping;

	pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
	return 0;
}

/**
 * arm_iommu_attach_device
 * @dev: valid struct device pointer
 * @mapping: io address space mapping structure (returned from
 *	arm_iommu_create_mapping)
 *
 * Attaches specified io address space mapping to the provided device.
 * This replaces the dma operations (dma_map_ops pointer) with the
 * IOMMU aware version.
 *
 * More than one client might be attached to the same io address space
 * mapping.
 */
int arm_iommu_attach_device(struct device *dev,
			    struct dma_iommu_mapping *mapping)
{
	int err;

	err = __arm_iommu_attach_device(dev, mapping);
	if (err)
		return err;

	set_dma_ops(dev, &iommu_ops);
	return 0;
}
EXPORT_SYMBOL_GPL(arm_iommu_attach_device);

static void __arm_iommu_detach_device(struct device *dev)
{
	struct dma_iommu_mapping *mapping;

	mapping = to_dma_iommu_mapping(dev);
	if (!mapping) {
		dev_warn(dev, "Not attached\n");
		return;
	}

	iommu_detach_device(mapping->domain, dev);
	kref_put(&mapping->kref, release_iommu_mapping);
	to_dma_iommu_mapping(dev) = NULL;

	pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
}

/**
 * arm_iommu_detach_device
 * @dev: valid struct device pointer
 *
 * Detaches the provided device from a previously attached map.
 * This voids the dma operations (dma_map_ops pointer)
 */
void arm_iommu_detach_device(struct device *dev)
{
	__arm_iommu_detach_device(dev);
	set_dma_ops(dev, NULL);
}
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);

static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
{
	return coherent ? &iommu_coherent_ops : &iommu_ops;
}

static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
				    struct iommu_ops *iommu)
{
	struct dma_iommu_mapping *mapping;

	if (!iommu)
		return false;

	mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
	if (IS_ERR(mapping)) {
		pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
				size, dev_name(dev));
		return false;
	}

	if (__arm_iommu_attach_device(dev, mapping)) {
		pr_warn("Failed to attached device %s to IOMMU_mapping\n",
				dev_name(dev));
		arm_iommu_release_mapping(mapping);
		return false;
	}

	return true;
}

static void arm_teardown_iommu_dma_ops(struct device *dev)
{
	struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);

	if (!mapping)
		return;

	__arm_iommu_detach_device(dev);
	arm_iommu_release_mapping(mapping);
}

#else

static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
				    struct iommu_ops *iommu)
{
	return false;
}

static void arm_teardown_iommu_dma_ops(struct device *dev) { }

#define arm_get_iommu_dma_map_ops arm_get_dma_map_ops

#endif	/* CONFIG_ARM_DMA_USE_IOMMU */

static struct dma_map_ops *arm_get_dma_map_ops(bool coherent)
{
	return coherent ? &arm_coherent_dma_ops : &arm_dma_ops;
}

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
			struct iommu_ops *iommu, bool coherent)
{
	struct dma_map_ops *dma_ops;

	dev->archdata.dma_coherent = coherent;
	if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu))
		dma_ops = arm_get_iommu_dma_map_ops(coherent);
	else
		dma_ops = arm_get_dma_map_ops(coherent);

	set_dma_ops(dev, dma_ops);
}

void arch_teardown_dma_ops(struct device *dev)
{
	arm_teardown_iommu_dma_ops(dev);
}