]> git.neil.brown.name Git - history.git/commitdiff
ppc64: Add the PowerMac PCI support
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 13 Feb 2004 02:24:50 +0000 (13:24 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 13 Feb 2004 02:24:50 +0000 (13:24 +1100)
This involves moving the final fixup to a function pointer in machdep,
turning all the PCI DMA routines into function pointers in a separate
structure and a bit of renaming work. The PowerMac currently use
"direct" PCI DMA bypassing the iommu. The driver for the IOMMU will
come later, allowing us to lift the limitation to 2Gb of RAM

arch/ppc64/kernel/chrp_setup.c
arch/ppc64/kernel/iSeries_pci.c
arch/ppc64/kernel/iSeries_setup.c
arch/ppc64/kernel/pSeries_pci.c
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/pci_dma.c
arch/ppc64/kernel/pci_dn.c
include/asm-ppc64/machdep.h
include/asm-ppc64/pci-bridge.h
include/asm-ppc64/pci.h
include/asm-ppc64/pci_dma.h

index 2a0df2e5ba7f69e137a15bef3ff0efbfef13e1ba..c7f89af4de9ec0732b0ca2130fc2a8568777031f 100644 (file)
@@ -70,6 +70,7 @@ void chrp_progress(char *, unsigned short);
 extern void openpic_init_IRQ(void);
 
 extern void find_and_init_phbs(void);
+extern void pSeries_final_fixup(void);
 
 extern void pSeries_get_boot_time(struct rtc_time *rtc_time);
 extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
@@ -265,6 +266,8 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
 
        ppc_md.init           = chrp_init2;
 
+       ppc_md.pcibios_fixup  = pSeries_final_fixup;
+
        ppc_md.restart        = rtas_restart;
        ppc_md.power_off      = rtas_power_off;
        ppc_md.halt           = rtas_halt;
index f5bc53b3a8d71fa3882672c9a86bd7d141f3a3f0..9a07bbb6724dd635eb44e2238ff5afc1619c7f5b 100644 (file)
@@ -241,9 +241,9 @@ void iSeries_pcibios_init(void)
 }
 
 /*
- * pcibios_final_fixup(void)  
+ * iSeries_pci_final_fixup(void)  
  */
-void __init pcibios_final_fixup(void)
+void __init iSeries_pci_final_fixup(void)
 {
        struct pci_dev *pdev = NULL;
        struct iSeries_Device_Node *node;
index bf234f5ec4ce46632a28b059023612d204331aff..2928075ab6feba8b5fe919e293b171a4ddd0441d 100644 (file)
@@ -63,10 +63,11 @@ extern void tce_init_iSeries(void);
 static void build_iSeries_Memory_Map(void);
 static void setup_iSeries_cache_sizes(void);
 static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
-void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa,
-               pte_t *ptep, unsigned hpteflags, unsigned bolted);
+extern void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa,
+                            pte_t *ptep, unsigned hpteflags, unsigned bolted);
 static void iSeries_setup_dprofile(void);
-void iSeries_setup_arch(void);
+extern void iSeries_setup_arch(void);
+extern void iSeries_pci_final_fixup(void);
 
 /* Global Variables */
 static unsigned long procFreqHz;
@@ -318,6 +319,8 @@ void __init iSeries_init_early(void)
        ppc_md.get_irq = iSeries_get_irq;
        ppc_md.init = NULL;
 
+       ppc_md.pcibios_fixup  = iSeries_pci_final_fixup;
+
        ppc_md.restart = iSeries_restart;
        ppc_md.power_off = iSeries_power_off;
        ppc_md.halt = iSeries_halt;
index 69e259d35c83dab3cfc41aa84febde0e47042f65..458d65cca89eeadc38b52b47eb1a646333c3791e 100644 (file)
@@ -687,7 +687,7 @@ static void phbs_fixup_io(void)
 
 extern void chrp_request_regions(void);
 
-void __init pcibios_final_fixup(void)
+void __init pSeries_final_fixup(void)
 {
        struct pci_dev *dev = NULL;
 
index f37fc0aa3f2f0759fca3ef049e2563f3f29b3995..ce83d1dd450728543c12dc23788222a2f2e14ddb 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
+#include <asm/machdep.h>
 
 #include "pci.h"
 
@@ -58,21 +59,32 @@ void pcibios_name_device(struct pci_dev* dev);
 void pcibios_final_fixup(void);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static void fixup_windbond_82c105(struct pci_dev* dev);
+extern void fixup_k2_sata(struct pci_dev* dev);
 
 void iSeries_pcibios_init(void);
 
 struct pci_controller *hose_head;
 struct pci_controller **hose_tail = &hose_head;
 
+struct pci_dma_ops pci_dma_ops;
+EXPORT_SYMBOL(pci_dma_ops);
+
 int global_phb_number;         /* Global phb counter */
 
 /* Cached ISA bridge dev. */
 struct pci_dev *ppc64_isabridge_dev = NULL;
 
 struct pci_fixup pcibios_fixups[] = {
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_TRIDENT,  PCI_ANY_ID, fixup_broken_pcnet32 },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_WINBOND,  PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 },
-       { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_TRIDENT,          PCI_ANY_ID,
+         fixup_broken_pcnet32 },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_WINBOND,          PCI_DEVICE_ID_WINBOND_82C105,
+         fixup_windbond_82c105 },
+       { PCI_FIXUP_HEADER,     PCI_ANY_ID,                     PCI_ANY_ID,
+         pcibios_name_device },
+#ifdef CONFIG_PPC_PMAC
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SERVERWORKS,      0x0240,
+         fixup_k2_sata },
+#endif
        { 0 }
 };
 
@@ -250,6 +262,9 @@ pci_alloc_pci_controller(enum phb_types controller_type)
        case phb_type_winnipeg:
                model = "PHB WP";
                break;
+       case phb_type_apple:
+               model = "PHB APPLE";
+               break;
        default:
                model = "PHB UK";
                break;
@@ -332,8 +347,9 @@ static int __init pcibios_init(void)
                pci_assign_unassigned_resources();
 #endif
 
-       /* Call machine dependent fixup */
-       pcibios_final_fixup();
+       /* Call machine dependent final fixup */
+       if (ppc_md.pcibios_fixup)
+               ppc_md.pcibios_fixup();
 
        /* Cache the location of the ISA bridge (if we have one) */
        ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
index 0d054e36d03a808d85c996143fb3dd7360a1dc85..64edeba4ba0d40796e23106ccf81ca23d2a4520f 100644 (file)
@@ -1002,7 +1002,7 @@ static void getTceTableParmsPSeriesLP(struct pci_controller *phb,
  * Returns the virtual address of the buffer and sets dma_handle
  * to the dma address (tce) of the first page.
  */
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+static void *tce_alloc_consistent(struct pci_dev *hwdev, size_t size,
                           dma_addr_t *dma_handle)
 {
        struct TceTable * tbl;
@@ -1055,7 +1055,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
        return ret;
 }
 
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+static void tce_free_consistent(struct pci_dev *hwdev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
 {
        struct TceTable * tbl;
@@ -1089,7 +1089,7 @@ void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  * need not be page aligned, the dma_addr_t returned will point to the same
  * byte within the page as vaddr.
  */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr, 
+static dma_addr_t tce_map_single(struct pci_dev *hwdev, void *vaddr, 
                          size_t size, int direction )
 {
        struct TceTable * tbl;
@@ -1124,7 +1124,7 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr,
        return dma_handle;
 }
 
-void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
+static void tce_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
 {
        struct TceTable * tbl;
        unsigned order, nPages;
@@ -1354,7 +1354,7 @@ static dma_addr_t create_tces_sg( struct TceTable *tbl, struct scatterlist *sg,
        return dmaAddr;
 }
 
-int pci_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction )
+static int tce_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction )
 {
        struct TceTable * tbl;
        unsigned numTces;
@@ -1389,7 +1389,7 @@ int pci_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int di
        return num_dma;
 }
 
-void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
+static void tce_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
 {
        struct TceTable * tbl;
        unsigned order, numTces, i;
@@ -1430,7 +1430,7 @@ void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int
 
 }
 #else
-int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
+static int tce_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
               int direction)
 {
        int i;
@@ -1448,7 +1448,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
        return nelems;
 }
 
-void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
+static void tce_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
                  int direction)
 {
        while (nelems--) {
@@ -1465,7 +1465,15 @@ void tce_init_pSeries(void)
 {
        ppc_md.tce_build = tce_build_pSeries;
        ppc_md.tce_free_one = tce_free_one_pSeries;
+
+       pci_dma_ops.pci_alloc_consistent = tce_alloc_consistent;
+       pci_dma_ops.pci_free_consistent = tce_free_consistent;
+       pci_dma_ops.pci_map_single = tce_map_single;
+       pci_dma_ops.pci_unmap_single = tce_unmap_single;
+       pci_dma_ops.pci_map_sg = tce_map_sg;
+       pci_dma_ops.pci_unmap_sg = tce_unmap_sg;
 }
+
 #endif
 
 #ifdef CONFIG_PPC_ISERIES
@@ -1473,5 +1481,12 @@ void tce_init_iSeries(void)
 {
        ppc_md.tce_build = tce_build_iSeries;
        ppc_md.tce_free_one = tce_free_one_iSeries;
+
+       pci_dma_ops.pci_alloc_consistent = tce_alloc_consistent;
+       pci_dma_ops.pci_free_consistent = tce_free_consistent;
+       pci_dma_ops.pci_map_single = tce_map_single;
+       pci_dma_ops.pci_unmap_single = tce_unmap_single;
+       pci_dma_ops.pci_map_sg = tce_map_sg;
+       pci_dma_ops.pci_unmap_sg = tce_unmap_sg;
 }
 #endif
index c809d73010913b33a7add5da110d5d429602e546..7b7d7efcfa63da01433a159c90b42e6a78f9e3a3 100644 (file)
@@ -181,6 +181,7 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev)
        }
        return dn;
 }
+EXPORT_SYMBOL(fetch_dev_dn);
 
 
 /******************************************************************
index e747011fab751d6cbd0a9f04ad916b15e50f6f68..3c2af66260eafc7bd98a371c7216b4fcee60d878 100644 (file)
@@ -69,6 +69,9 @@ struct machdep_calls {
        void            (*init_IRQ)(void);
        int             (*get_irq)(struct pt_regs *);
 
+       /* PCI stuff */
+       void            (*pcibios_fixup)(void);
+
        /* Optional, may be NULL. */
        void            (*init)(void);
 
index 33933158cc515054510ad3aae6f76d6950fbaf87..a092b9cae621df9e51569b70a9771b607a9e512f 100644 (file)
@@ -21,7 +21,8 @@ enum phb_types {
        phb_type_hypervisor = 0x1,
        phb_type_python     = 0x10,
        phb_type_speedwagon = 0x11,
-       phb_type_winnipeg   = 0x12
+       phb_type_winnipeg   = 0x12,
+       phb_type_apple      = 0xff
 };
 
 /*
@@ -47,6 +48,8 @@ struct pci_controller {
        unsigned long pci_io_offset;
 
        struct pci_ops *ops;
+       volatile unsigned int *cfg_addr;
+       volatile unsigned char *cfg_data;
 
        /* Currently, we limit ourselves to 1 IO range and 3 mem
         * ranges since the common pci_bus structure can't handle more
index 835b882fb18dc45de74e2d58ac92cfbec19fa45c..f2e5f70a40026dc13afb062da1c3b57a7f720758 100644 (file)
@@ -55,19 +55,62 @@ static inline int pcibios_prep_mwi(struct pci_dev *dev)
 
 extern unsigned int pcibios_assign_all_busses(void);
 
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-                                 dma_addr_t *dma_handle);
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-                               void *vaddr, dma_addr_t dma_handle);
-
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-                                size_t size, int direction);
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                             size_t size, int direction);
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                      int nents, int direction);
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                         int nents, int direction);
+/*
+ * PCI DMA operations are abstracted for G5 vs. i/pSeries
+ */
+struct pci_dma_ops {
+       void *          (*pci_alloc_consistent)(struct pci_dev *hwdev, size_t size,
+                                       dma_addr_t *dma_handle);
+       void            (*pci_free_consistent)(struct pci_dev *hwdev, size_t size,
+                                      void *vaddr, dma_addr_t dma_handle);
+
+       dma_addr_t      (*pci_map_single)(struct pci_dev *hwdev, void *ptr,
+                                         size_t size, int direction);
+       void            (*pci_unmap_single)(struct pci_dev *hwdev, dma_addr_t dma_addr,
+                                           size_t size, int direction);
+       int             (*pci_map_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
+                                     int nents, int direction);
+       void            (*pci_unmap_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
+                                       int nents, int direction);
+};
+
+extern struct pci_dma_ops pci_dma_ops;
+
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                                        dma_addr_t *dma_handle)
+{
+       return pci_dma_ops.pci_alloc_consistent(hwdev, size, dma_handle);
+}
+
+static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+                                      void *vaddr, dma_addr_t dma_handle)
+{
+       pci_dma_ops.pci_free_consistent(hwdev, size, vaddr, dma_handle);
+}
+
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+                                       size_t size, int direction)
+{
+       return pci_dma_ops.pci_map_single(hwdev, ptr, size, direction); 
+}
+
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+                                   size_t size, int direction)
+{
+       pci_dma_ops.pci_unmap_single(hwdev, dma_addr, size, direction);
+}
+
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+                            int nents, int direction)
+{
+       return pci_dma_ops.pci_map_sg(hwdev, sg, nents, direction);
+}
+
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+                               int nents, int direction)
+{
+       pci_dma_ops.pci_unmap_sg(hwdev, sg, nents, direction);
+}
 
 static inline void pci_dma_sync_single(struct pci_dev *hwdev,
                                       dma_addr_t dma_handle,
index 7b88d2c358384e821a413eeacbc911b6e2bb3920..bee2fc242da66af5c36c0f8955161e95612404c1 100644 (file)
@@ -94,7 +94,9 @@ extern struct TceTable virtBusTceTable;       /* Tce table for virtual bus */
 extern void create_tce_tables(void);
 extern void create_pci_bus_tce_table(unsigned long);
 
-void tce_init_pSeries(void);
-void tce_init_iSeries(void);
+extern void tce_init_pSeries(void);
+extern void tce_init_iSeries(void);
+
+extern void pci_dma_init_direct(void);
 
 #endif