ppc64: Add the PowerMac PCI support

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
parent aeadc4a5
......@@ -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;
......
......@@ -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;
......
......@@ -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,
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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......@@ -181,6 +181,7 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev)
}
return dn;
}
EXPORT_SYMBOL(fetch_dev_dn);
/******************************************************************
......
......@@ -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);
......
......@@ -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
......
......@@ -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,
/*
* 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);
extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
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,
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,
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 (*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,
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,
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment