aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorFengguang Wu <wfg@mail.ustc.edu.cn>2007-07-19 04:48:02 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:44 -0400
commit3ea89ee86a82e9fbde37018d9b9e92a552e5fd13 (patch)
tree5fef7216ef39d66684754e4aadf368ce9adfd72e /mm
parent122a21d11cbfda6d1e33cbc8ae9e4c4ee2f1886e (diff)
readahead: convert filemap invocations
Convert filemap reads to use on-demand readahead. The new call scheme is to - call readahead on non-cached page - call readahead on look-ahead page - update prev_index when finished with the read request Signed-off-by: Fengguang Wu <wfg@mail.ustc.edu.cn> Cc: Steven Pratt <slpratt@austin.ibm.com> Cc: Ram Pai <linuxram@us.ibm.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c51
1 files changed, 31 insertions, 20 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index 4fd9e3f0f48a..5eb0a6b9d607 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -891,15 +891,20 @@ void do_generic_mapping_read(struct address_space *mapping,
891 unsigned long nr, ret; 891 unsigned long nr, ret;
892 892
893 cond_resched(); 893 cond_resched();
894 if (index == next_index)
895 next_index = page_cache_readahead(mapping, &ra, filp,
896 index, last_index - index);
897
898find_page: 894find_page:
899 page = find_get_page(mapping, index); 895 page = find_get_page(mapping, index);
900 if (unlikely(page == NULL)) { 896 if (!page) {
901 handle_ra_miss(mapping, &ra, index); 897 page_cache_readahead_ondemand(mapping,
902 goto no_cached_page; 898 &ra, filp, page,
899 index, last_index - index);
900 page = find_get_page(mapping, index);
901 if (unlikely(page == NULL))
902 goto no_cached_page;
903 }
904 if (PageReadahead(page)) {
905 page_cache_readahead_ondemand(mapping,
906 &ra, filp, page,
907 index, last_index - index);
903 } 908 }
904 if (!PageUptodate(page)) 909 if (!PageUptodate(page))
905 goto page_not_up_to_date; 910 goto page_not_up_to_date;
@@ -1051,6 +1056,7 @@ no_cached_page:
1051 1056
1052out: 1057out:
1053 *_ra = ra; 1058 *_ra = ra;
1059 _ra->prev_index = prev_index;
1054 1060
1055 *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; 1061 *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
1056 if (cached_page) 1062 if (cached_page)
@@ -1333,26 +1339,30 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1333 goto no_cached_page; 1339 goto no_cached_page;
1334 1340
1335 /* 1341 /*
1336 * The readahead code wants to be told about each and every page
1337 * so it can build and shrink its windows appropriately
1338 *
1339 * For sequential accesses, we use the generic readahead logic.
1340 */
1341 if (VM_SequentialReadHint(vma))
1342 page_cache_readahead(mapping, ra, file, vmf->pgoff, 1);
1343
1344 /*
1345 * Do we have something in the page cache already? 1342 * Do we have something in the page cache already?
1346 */ 1343 */
1347retry_find: 1344retry_find:
1348 page = find_lock_page(mapping, vmf->pgoff); 1345 page = find_lock_page(mapping, vmf->pgoff);
1346 /*
1347 * For sequential accesses, we use the generic readahead logic.
1348 */
1349 if (VM_SequentialReadHint(vma)) {
1350 if (!page) {
1351 page_cache_readahead_ondemand(mapping, ra, file, page,
1352 vmf->pgoff, 1);
1353 page = find_lock_page(mapping, vmf->pgoff);
1354 if (!page)
1355 goto no_cached_page;
1356 }
1357 if (PageReadahead(page)) {
1358 page_cache_readahead_ondemand(mapping, ra, file, page,
1359 vmf->pgoff, 1);
1360 }
1361 }
1362
1349 if (!page) { 1363 if (!page) {
1350 unsigned long ra_pages; 1364 unsigned long ra_pages;
1351 1365
1352 if (VM_SequentialReadHint(vma)) {
1353 handle_ra_miss(mapping, ra, vmf->pgoff);
1354 goto no_cached_page;
1355 }
1356 ra->mmap_miss++; 1366 ra->mmap_miss++;
1357 1367
1358 /* 1368 /*
@@ -1405,6 +1415,7 @@ retry_find:
1405 * Found the page and have a reference on it. 1415 * Found the page and have a reference on it.
1406 */ 1416 */
1407 mark_page_accessed(page); 1417 mark_page_accessed(page);
1418 ra->prev_index = page->index;
1408 vmf->page = page; 1419 vmf->page = page;
1409 return ret | VM_FAULT_LOCKED; 1420 return ret | VM_FAULT_LOCKED;
1410 1421
davem@sunset.davemloft.net> 2006-02-10 03:08:26 -0500 committer David S. Miller <davem@sunset.davemloft.net> 2006-03-20 04:12:15 -0500 [SPARC64]: First cut at SUN4V PCI IOMMU handling.' href='/cgit/cgit.cgi/litmus-rt.git/commit/arch/sparc64/kernel/pci_sun4v.c?h=v2.6.37-rc4&id=18397944642cbca7fcd4a109b43ed5b4652e95b9'>18397944642c
ad7ad57c6127
18397944642c

d284142cbad6
18397944642c

d284142cbad6

18397944642c





6a32fd4d0d42
18397944642c
ad7ad57c6127



18397944642c
6a32fd4d0d42
ad7ad57c6127
6a32fd4d0d42


18397944642c
ad7ad57c6127
6a32fd4d0d42
18397944642c
6a32fd4d0d42
18397944642c

6a32fd4d0d42



d284142cbad6
6a32fd4d0d42

d284142cbad6
6a32fd4d0d42

8f6a93a196ba

ad7ad57c6127

8f6a93a196ba
a2fb23af1c31
16ce82d846f2
7c8f486ae7fe

18397944642c

ad7ad57c6127

a2fb23af1c31
18397944642c



d284142cbad6
18397944642c














8f6a93a196ba

ad7ad57c6127

8f6a93a196ba
16ce82d846f2
18397944642c
7c8f486ae7fe
6a32fd4d0d42
18397944642c

18397944642c
ad7ad57c6127
18397944642c
ad7ad57c6127
18397944642c




18397944642c

d284142cbad6
18397944642c

d284142cbad6
18397944642c






ad7ad57c6127
18397944642c

6a32fd4d0d42
18397944642c
ad7ad57c6127
18397944642c
6a32fd4d0d42
ad7ad57c6127
6a32fd4d0d42


ad7ad57c6127
6a32fd4d0d42
18397944642c
6a32fd4d0d42
18397944642c





ad7ad57c6127
6a32fd4d0d42



d284142cbad6
6a32fd4d0d42

ad7ad57c6127
8f6a93a196ba

ad7ad57c6127

8f6a93a196ba
a2fb23af1c31
16ce82d846f2
7c8f486ae7fe
18397944642c
7c8f486ae7fe
18397944642c
ad7ad57c6127
18397944642c




ad7ad57c6127

a2fb23af1c31
18397944642c






d284142cbad6
18397944642c
d284142cbad6
18397944642c











ad7ad57c6127

8f6a93a196ba
13fa14e18561




16ce82d846f2
13fa14e18561


18397944642c
ad7ad57c6127
13fa14e18561

18397944642c
13fa14e18561


18397944642c
13fa14e18561



18397944642c
13fa14e18561

18397944642c
13fa14e18561
18397944642c
13fa14e18561
18397944642c
13fa14e18561


38192d52f159
13fa14e18561









38192d52f159
13fa14e18561






38192d52f159
13fa14e18561
38192d52f159
13fa14e18561



38192d52f159
13fa14e18561
38192d52f159
13fa14e18561
38192d52f159
13fa14e18561
38192d52f159
13fa14e18561















38192d52f159
13fa14e18561
38192d52f159
13fa14e18561



38192d52f159
13fa14e18561


38192d52f159



6a32fd4d0d42

18397944642c
13fa14e18561
18397944642c
13fa14e18561






6a32fd4d0d42

13fa14e18561













6a32fd4d0d42


8f6a93a196ba

ad7ad57c6127

8f6a93a196ba
a2fb23af1c31
13fa14e18561
16ce82d846f2
13fa14e18561

18397944642c
13fa14e18561
18397944642c
ad7ad57c6127

a2fb23af1c31
18397944642c
18397944642c

13fa14e18561



















18397944642c
13fa14e18561

18397944642c

8f6a93a196ba

ad7ad57c6127


8f6a93a196ba
18397944642c
8f6a93a196ba

ad7ad57c6127


8f6a93a196ba
18397944642c
8f6a93a196ba

ad7ad57c6127








8f6a93a196ba

a1f35ba374bc
bade56221671
e87dc35020bc


34768bc83291



c26092675020

bade56221671

4c6222587118

18397944642c
9b3627f389c0
e7a0453ef82c
7c8f486ae7fe
18397944642c







e7a0453ef82c
c2a5a46be4a1






e7a0453ef82c
18397944642c
e7a0453ef82c

18397944642c

4c6222587118
bade56221671
16ce82d846f2
e87dc35020bc
59db8102bd0a
18397944642c
e87dc35020bc



18397944642c
e87dc35020bc


18397944642c




59db8102bd0a



18397944642c

59db8102bd0a


18397944642c









59db8102bd0a
18397944642c
982c2064d9a8
18397944642c



18397944642c

e7a0453ef82c
c2a5a46be4a1


bade56221671

35a17eb6a87c


























e5dd42e4fb24
35a17eb6a87c
















759f89e03c9e

35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e





















35a17eb6a87c
759f89e03c9e



35a17eb6a87c
759f89e03c9e






35a17eb6a87c
759f89e03c9e

35a17eb6a87c
759f89e03c9e



35a17eb6a87c
759f89e03c9e
35a17eb6a87c

759f89e03c9e

35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e


35a17eb6a87c
759f89e03c9e

35a17eb6a87c
759f89e03c9e










35a17eb6a87c


759f89e03c9e
35a17eb6a87c
759f89e03c9e








35a17eb6a87c

759f89e03c9e
35a17eb6a87c




















































759f89e03c9e
35a17eb6a87c
759f89e03c9e
35a17eb6a87c

759f89e03c9e

35a17eb6a87c
759f89e03c9e
35a17eb6a87c
7fe3730de729
759f89e03c9e


35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e
35a17eb6a87c

759f89e03c9e


35a17eb6a87c
759f89e03c9e
35a17eb6a87c
759f89e03c9e

35a17eb6a87c
759f89e03c9e



35a17eb6a87c
759f89e03c9e
35a17eb6a87c
e9870c4c0aef
759f89e03c9e










e9870c4c0aef

759f89e03c9e
e9870c4c0aef
35a17eb6a87c





a1f35ba374bc

bade56221671

bade56221671
3833789bb2e1



bade56221671
34768bc83291



ca3dd88e4116

34768bc83291
6c108f129975

bade56221671
e87dc35020bc
bade56221671
3833789bb2e1
bade56221671
e87dc35020bc
bade56221671
e87dc35020bc
bade56221671
9fd8b64761d3
bade56221671
cfa0652c4eb4
bade56221671
35a17eb6a87c
bade56221671

f0429bf7a099
8f6a93a196ba
e01c0d6d8cf2
bade56221671
34768bc83291
16ce82d846f2
e87dc35020bc

7c8f486ae7fe

3833789bb2e1
e01c0d6d8cf2











ad7ad57c6127

e01c0d6d8cf2

e87dc35020bc
75c6d1410caa



e87dc35020bc


3833789bb2e1
34768bc83291
0b522497a176
34768bc83291
0b522497a176

3833789bb2e1
bade56221671
a283a5252056
7c8f486ae7fe




ad7ad57c6127
bade56221671
7c8f486ae7fe
982c2064d9a8
7c8f486ae7fe


16ce82d846f2
7c8f486ae7fe


bade56221671

16ce82d846f2
7c8f486ae7fe


bade56221671

e87dc35020bc
7c8f486ae7fe




8f6a93a196ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990

                                                      
                                                                       







                            
                         

                      
                       
 





                           
                     



                         

                      


                                    
                                                 
 
                    
                                                                          



                                                                          

  
                                                       

                                   
                                                                                                 
 
                                                            
 
                              





                                   
                                                    
 
                                                                    
                                                 




                                         
                             





                                                                            
                                                                         









                                                                               
         






                         










                                                             
                                   
                                                 
 
                                                            




                                           
                                            




                                   
                                        
 
                                                            


                                          
                                    
 
 

                                                                    
 
                            
                                                          

                   


                                   
                                         


                                       
 
                                                  
                                        
                            
 

                                                          
                                    

                                               
                                                            

                                                    

                                              





                                                  
                              
 



                                                  
 
                                      
                                                                         


                                            
 
                                             
                                    
 
                                 

                   



                                       
                                                    

                                                    
                 

                                      

 

                                                                            
 
                                 
                            

                                                  

                                                      

                                            
                                   



                                                                       
                                              














                                                                              

 

                                                                             
 
                            
                                           
                                    
                          

                           
 
                                    
 
                                            




                                                                    

                                               
                                                            

                                                    
                                              






                                                 
                                       

                                              
                              
 
                                            
 
                                                                  
                                                       


                                            
                                             
                                    
 
                                 





                               
                              



                                       
                                                  

                                                    
                              

 

                                                                             
 
                                 
                            
                                    
                   
                      
 
                                              




                                       

                                            
                                   






                                                                          
                                                  
 
                                                                         











                                                                              

                                                                        
 




                                                
                            


                                      
 
                                    

                                  
        


                                              
 



                                         
 

                                                              
 
                                               
 
                                           
 


                                                         
 









                                                                       
 






                                                                                         
 
                                             
 



                                                        
 
                                          
                                      
                                  
                                                     
                                               
                                                      















                                                                                       
                         
                 
 



                                                                 
                 


                                                                      



                                

                                      
 
                                                    
 






                                                   

                 













                                                                                


                                                    

 

                                                                           
 
                                 
                               
                            

                            
 
                                      
 

                                            
                                   
        

                                               



















                                                                                      
 

                                 

                                                    

 


                                                                         
 
                              

 


                                                                          
 
                              

 








                                                                     

  
                                                               
 


                               



                                                           

                                                       

 

                                                                            
 
                                                  
                                 
                      







                                                                
                                    






                                                                             
                 
         

                   

 
                                                                 
 
                                         
                              
                                                   
                                          



                                                                     
 


                                 




                                                      



                                                                           

          


                                                       









                                                         
                                       
                               
                                                   



                                                                              

                                             
                                                


                                                                 

 


























                                                            
                                                              
















                                                                    

                                                                             
 
                                 
 
                                                                   
                          
                              
 





















                                                                           
 



                                                                      
 






                                                                
 

                                            
 



                                                                        
 
                 

 

                                                                             
 
                          
 


                                                                   
 

                 
 










                                                                              


                 
                                                                              
 








                                                                         

 
                                                         




















































                                                                               
                                                         
 
                                                       

              

                                                           
 
                                                                           
         
 


                                                                           
 
                                                
 
                                 
 
                               

 


                                                             
 
                                                                        
 

                               
 



                                                                               
 
                        
 
 










                                                           

                                                        
                                                       
 





                                                        

                                                                            

                                 
 



                                
 



                                           

                                        
 

                                    
                        
                            
 
                                   
 
                                  
 
                                                        
 
                                        
 
                               
                                  
                                

 
                                                                    
 
                                        
                                      
                                 
                            

                                            

                      
 











                                                                             

                                         

         
                                                 



                                                                            


                                                           
 
                                                        
                                                           
                                                                       

                               
         
 
                                  




                                                                 
                                                              
         
 
                                                                    


                                        
                                                          


                                        

                               
                                                          


                                        

                               
                                             




                                                                   
 
/* pci_sun4v.c: SUN4V specific PCI controller support.
 *
 * Copyright (C) 2006, 2007, 2008 David S. Miller (davem@davemloft.net)
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/irq.h>
#include <linux/msi.h>
#include <linux/log2.h>

#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/oplib.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>

#include "pci_impl.h"
#include "iommu_common.h"

#include "pci_sun4v.h"

static unsigned long vpci_major = 1;
static unsigned long vpci_minor = 1;

#define PGLIST_NENTS	(PAGE_SIZE / sizeof(u64))

struct iommu_batch {
	struct device	*dev;		/* Device mapping is for.	*/
	unsigned long	prot;		/* IOMMU page protections	*/
	unsigned long	entry;		/* Index into IOTSB.		*/
	u64		*pglist;	/* List of physical pages	*/
	unsigned long	npages;		/* Number of pages in list.	*/
};

static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);

/* Interrupts must be disabled.  */
static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
{
	struct iommu_batch *p = &__get_cpu_var(iommu_batch);

	p->dev		= dev;
	p->prot		= prot;
	p->entry	= entry;
	p->npages	= 0;
}

/* Interrupts must be disabled.  */
static long iommu_batch_flush(struct iommu_batch *p)
{
	struct pci_pbm_info *pbm = p->dev->archdata.host_controller;
	unsigned long devhandle = pbm->devhandle;
	unsigned long prot = p->prot;
	unsigned long entry = p->entry;
	u64 *pglist = p->pglist;
	unsigned long npages = p->npages;

	while (npages != 0) {
		long num;

		num = pci_sun4v_iommu_map(devhandle, HV_PCI_TSBID(0, entry),
					  npages, prot, __pa(pglist));
		if (unlikely(num < 0)) {
			if (printk_ratelimit())
				printk("iommu_batch_flush: IOMMU map of "
				       "[%08lx:%08lx:%lx:%lx:%lx] failed with "
				       "status %ld\n",
				       devhandle, HV_PCI_TSBID(0, entry),
				       npages, prot, __pa(pglist), num);
			return -1;
		}

		entry += num;
		npages -= num;
		pglist += num;
	}

	p->entry = entry;
	p->npages = 0;

	return 0;
}

static inline void iommu_batch_new_entry(unsigned long entry)
{
	struct iommu_batch *p = &__get_cpu_var(iommu_batch);

	if (p->entry + p->npages == entry)
		return;
	if (p->entry != ~0UL)
		iommu_batch_flush(p);
	p->entry = entry;
}

/* Interrupts must be disabled.  */
static inline long iommu_batch_add(u64 phys_page)
{
	struct iommu_batch *p = &__get_cpu_var(iommu_batch);

	BUG_ON(p->npages >= PGLIST_NENTS);

	p->pglist[p->npages++] = phys_page;
	if (p->npages == PGLIST_NENTS)
		return iommu_batch_flush(p);

	return 0;
}

/* Interrupts must be disabled.  */
static inline long iommu_batch_end(void)
{
	struct iommu_batch *p = &__get_cpu_var(iommu_batch);

	BUG_ON(p->npages >= PGLIST_NENTS);

	return iommu_batch_flush(p);
}

static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
				   dma_addr_t *dma_addrp, gfp_t gfp)
{
	struct iommu *iommu;
	unsigned long flags, order, first_page, npages, n;
	void *ret;
	long entry;

	size = IO_PAGE_ALIGN(size);
	order = get_order(size);
	if (unlikely(order >= MAX_ORDER))
		return NULL;

	npages = size >> IO_PAGE_SHIFT;

	first_page = __get_free_pages(gfp, order);
	if (unlikely(first_page == 0UL))
		return NULL;

	memset((char *)first_page, 0, PAGE_SIZE << order);

	iommu = dev->archdata.iommu;

	spin_lock_irqsave(&iommu->lock, flags);
	entry = iommu_range_alloc(dev, iommu, npages, NULL);
	spin_unlock_irqrestore(&iommu->lock, flags);

	if (unlikely(entry == DMA_ERROR_CODE))
		goto range_alloc_fail;

	*dma_addrp = (iommu->page_table_map_base +
		      (entry << IO_PAGE_SHIFT));
	ret = (void *) first_page;
	first_page = __pa(first_page);

	local_irq_save(flags);

	iommu_batch_start(dev,
			  (HV_PCI_MAP_ATTR_READ |
			   HV_PCI_MAP_ATTR_WRITE),
			  entry);

	for (n = 0; n < npages; n++) {
		long err = iommu_batch_add(first_page + (n * PAGE_SIZE));
		if (unlikely(err < 0L))
			goto iommu_map_fail;
	}

	if (unlikely(iommu_batch_end() < 0L))
		goto iommu_map_fail;

	local_irq_restore(flags);

	return ret;

iommu_map_fail:
	/* Interrupts are disabled.  */
	spin_lock(&iommu->lock);
	iommu_range_free(iommu, *dma_addrp, npages);
	spin_unlock_irqrestore(&iommu->lock, flags);

range_alloc_fail:
	free_pages(first_page, order);
	return NULL;
}

static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
				 dma_addr_t dvma)
{
	struct pci_pbm_info *pbm;
	struct iommu *iommu;
	unsigned long flags, order, npages, entry;
	u32 devhandle;

	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
	iommu = dev->archdata.iommu;
	pbm = dev->archdata.host_controller;
	devhandle = pbm->devhandle;
	entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);

	spin_lock_irqsave(&iommu->lock, flags);

	iommu_range_free(iommu, dvma, npages);

	do {
		unsigned long num;

		num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
					    npages);
		entry += num;
		npages -= num;
	} while (npages != 0);

	spin_unlock_irqrestore(&iommu->lock, flags);

	order = get_order(size);
	if (order < 10)
		free_pages((unsigned long)cpu, order);
}

static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
				    enum dma_data_direction direction)
{
	struct iommu *iommu;
	unsigned long flags, npages, oaddr;
	unsigned long i, base_paddr;
	u32 bus_addr, ret;
	unsigned long prot;
	long entry;

	iommu = dev->archdata.iommu;

	if (unlikely(direction == DMA_NONE))
		goto bad;

	oaddr = (unsigned long)ptr;
	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
	npages >>= IO_PAGE_SHIFT;

	spin_lock_irqsave(&iommu->lock, flags);
	entry = iommu_range_alloc(dev, iommu, npages, NULL);
	spin_unlock_irqrestore(&iommu->lock, flags);

	if (unlikely(entry == DMA_ERROR_CODE))
		goto bad;

	bus_addr = (iommu->page_table_map_base +
		    (entry << IO_PAGE_SHIFT));
	ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
	base_paddr = __pa(oaddr & IO_PAGE_MASK);
	prot = HV_PCI_MAP_ATTR_READ;
	if (direction != DMA_TO_DEVICE)
		prot |= HV_PCI_MAP_ATTR_WRITE;

	local_irq_save(flags);

	iommu_batch_start(dev, prot, entry);

	for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) {
		long err = iommu_batch_add(base_paddr);
		if (unlikely(err < 0L))
			goto iommu_map_fail;
	}
	if (unlikely(iommu_batch_end() < 0L))
		goto iommu_map_fail;

	local_irq_restore(flags);

	return ret;

bad:
	if (printk_ratelimit())
		WARN_ON(1);
	return DMA_ERROR_CODE;

iommu_map_fail:
	/* Interrupts are disabled.  */
	spin_lock(&iommu->lock);
	iommu_range_free(iommu, bus_addr, npages);
	spin_unlock_irqrestore(&iommu->lock, flags);

	return DMA_ERROR_CODE;
}

static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
				size_t sz, enum dma_data_direction direction)
{
	struct pci_pbm_info *pbm;
	struct iommu *iommu;
	unsigned long flags, npages;
	long entry;
	u32 devhandle;

	if (unlikely(direction == DMA_NONE)) {
		if (printk_ratelimit())
			WARN_ON(1);
		return;
	}

	iommu = dev->archdata.iommu;
	pbm = dev->archdata.host_controller;
	devhandle = pbm->devhandle;

	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
	npages >>= IO_PAGE_SHIFT;
	bus_addr &= IO_PAGE_MASK;

	spin_lock_irqsave(&iommu->lock, flags);

	iommu_range_free(iommu, bus_addr, npages);

	entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
	do {
		unsigned long num;

		num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
					    npages);
		entry += num;
		npages -= num;
	} while (npages != 0);

	spin_unlock_irqrestore(&iommu->lock, flags);
}

static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
			 int nelems, enum dma_data_direction direction)
{
	struct scatterlist *s, *outs, *segstart;
	unsigned long flags, handle, prot;
	dma_addr_t dma_next = 0, dma_addr;
	unsigned int max_seg_size;
	int outcount, incount, i;
	struct iommu *iommu;
	long err;

	BUG_ON(direction == DMA_NONE);

	iommu = dev->archdata.iommu;
	if (nelems == 0 || !iommu)
		return 0;
	
	prot = HV_PCI_MAP_ATTR_READ;
	if (direction != DMA_TO_DEVICE)
		prot |= HV_PCI_MAP_ATTR_WRITE;

	outs = s = segstart = &sglist[0];
	outcount = 1;
	incount = nelems;
	handle = 0;

	/* Init first segment length for backout at failure */
	outs->dma_length = 0;

	spin_lock_irqsave(&iommu->lock, flags);

	iommu_batch_start(dev, prot, ~0UL);

	max_seg_size = dma_get_max_seg_size(dev);
	for_each_sg(sglist, s, nelems, i) {
		unsigned long paddr, npages, entry, slen;

		slen = s->length;
		/* Sanity check */
		if (slen == 0) {
			dma_next = 0;
			continue;
		}
		/* Allocate iommu entries for that segment */
		paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
		npages = iommu_num_pages(paddr, slen);
		entry = iommu_range_alloc(dev, iommu, npages, &handle);

		/* Handle failure */
		if (unlikely(entry == DMA_ERROR_CODE)) {
			if (printk_ratelimit())
				printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx"
				       " npages %lx\n", iommu, paddr, npages);
			goto iommu_map_failed;
		}

		iommu_batch_new_entry(entry);

		/* Convert entry to a dma_addr_t */
		dma_addr = iommu->page_table_map_base +
			(entry << IO_PAGE_SHIFT);
		dma_addr |= (s->offset & ~IO_PAGE_MASK);

		/* Insert into HW table */
		paddr &= IO_PAGE_MASK;
		while (npages--) {
			err = iommu_batch_add(paddr);
			if (unlikely(err < 0L))
				goto iommu_map_failed;
			paddr += IO_PAGE_SIZE;
		}

		/* If we are in an open segment, try merging */
		if (segstart != s) {
			/* We cannot merge if:
			 * - allocated dma_addr isn't contiguous to previous allocation
			 */
			if ((dma_addr != dma_next) ||
			    (outs->dma_length + s->length > max_seg_size)) {
				/* Can't merge: create a new segment */
				segstart = s;
				outcount++;
				outs = sg_next(outs);
			} else {
				outs->dma_length += s->length;
			}
		}

		if (segstart == s) {
			/* This is a new segment, fill entries */
			outs->dma_address = dma_addr;
			outs->dma_length = slen;
		}

		/* Calculate next page pointer for contiguous check */
		dma_next = dma_addr + slen;
	}

	err = iommu_batch_end();

	if (unlikely(err < 0L))
		goto iommu_map_failed;

	spin_unlock_irqrestore(&iommu->lock, flags);

	if (outcount < incount) {
		outs = sg_next(outs);
		outs->dma_address = DMA_ERROR_CODE;
		outs->dma_length = 0;
	}

	return outcount;

iommu_map_failed:
	for_each_sg(sglist, s, nelems, i) {
		if (s->dma_length != 0) {
			unsigned long vaddr, npages;

			vaddr = s->dma_address & IO_PAGE_MASK;
			npages = iommu_num_pages(s->dma_address, s->dma_length);
			iommu_range_free(iommu, vaddr, npages);
			/* XXX demap? XXX */
			s->dma_address = DMA_ERROR_CODE;
			s->dma_length = 0;
		}
		if (s == outs)
			break;
	}
	spin_unlock_irqrestore(&iommu->lock, flags);

	return 0;
}

static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
			    int nelems, enum dma_data_direction direction)
{
	struct pci_pbm_info *pbm;
	struct scatterlist *sg;
	struct iommu *iommu;
	unsigned long flags;
	u32 devhandle;

	BUG_ON(direction == DMA_NONE);

	iommu = dev->archdata.iommu;
	pbm = dev->archdata.host_controller;
	devhandle = pbm->devhandle;
	
	spin_lock_irqsave(&iommu->lock, flags);

	sg = sglist;
	while (nelems--) {
		dma_addr_t dma_handle = sg->dma_address;
		unsigned int len = sg->dma_length;
		unsigned long npages, entry;

		if (!len)
			break;
		npages = iommu_num_pages(dma_handle, len);
		iommu_range_free(iommu, dma_handle, npages);

		entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
		while (npages) {
			unsigned long num;

			num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
						    npages);
			entry += num;
			npages -= num;
		}

		sg = sg_next(sg);
	}

	spin_unlock_irqrestore(&iommu->lock, flags);
}

static void dma_4v_sync_single_for_cpu(struct device *dev,
				       dma_addr_t bus_addr, size_t sz,
				       enum dma_data_direction direction)
{
	/* Nothing to do... */
}

static void dma_4v_sync_sg_for_cpu(struct device *dev,
				   struct scatterlist *sglist, int nelems,
				   enum dma_data_direction direction)
{
	/* Nothing to do... */
}

const struct dma_ops sun4v_dma_ops = {
	.alloc_coherent			= dma_4v_alloc_coherent,
	.free_coherent			= dma_4v_free_coherent,
	.map_single			= dma_4v_map_single,
	.unmap_single			= dma_4v_unmap_single,
	.map_sg				= dma_4v_map_sg,
	.unmap_sg			= dma_4v_unmap_sg,
	.sync_single_for_cpu		= dma_4v_sync_single_for_cpu,
	.sync_sg_for_cpu		= dma_4v_sync_sg_for_cpu,
};

static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
{
	struct property *prop;
	struct device_node *dp;

	dp = pbm->prom_node;
	prop = of_find_property(dp, "66mhz-capable", NULL);
	pbm->is_66mhz_capable = (prop != NULL);
	pbm->pci_bus = pci_scan_one_pbm(pbm);

	/* XXX register error interrupt handlers XXX */
}

static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,