Commit d64247f3 authored by Anton Blanchard's avatar Anton Blanchard

ppc64: new pci config methods, from Todd Inglett

parent bdc2b03d
...@@ -63,85 +63,85 @@ static int ibm_write_pci_config; ...@@ -63,85 +63,85 @@ static int ibm_write_pci_config;
static int s7a_workaround; static int s7a_workaround;
/****************************************************************************** static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
* {
* pSeries I/O Operations to access the PCI configuration space. unsigned long returnval = ~0L;
* unsigned long buid, addr;
*****************************************************************************/ int ret;
#define RTAS_PCI_READ_OP(size, type, nbytes) \
int \ if (!dn)
rtas_read_config_##size(struct device_node *dn, int offset, type val) { \ return -2;
unsigned long returnval = ~0L; \
unsigned long buid; \ addr = (dn->busno << 16) | (dn->devfn << 8) | where;
unsigned int addr; \ buid = dn->phb->buid;
int ret; \ if (buid) {
\ ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, size);
if (dn == NULL) { \ if (ret < 0|| (returnval == 0xffffffff))
ret = -2; \ ret = rtas_fake_read(dn, where, size, &returnval);
} else { \ } else {
addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \ ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
buid = dn->phb->buid; \ }
if (buid) { \ *val = returnval;
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \ return ret;
if (ret < 0|| (returnval == 0xffffffff)) \ }
ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
} else { \ static int rtas_pci_read_config(struct pci_bus *bus,
ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \ unsigned int devfn,
} \ int where, int size, u32 *val)
} \ {
*val = returnval; \ struct device_node *busdn, *dn;
return ret; \
} \ if (bus->self)
int \ busdn = pci_device_to_OF_node(bus->self);
rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) { \ else
struct device_node *dn = pci_device_to_OF_node(dev); \ busdn = bus->sysdata; /* must be a phb */
int ret = rtas_read_config_##size(dn, offset, val); \
/* udbg_printf("read bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \ /* Search only direct children of the bus */
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \ for (dn = busdn->child; dn; dn = dn->sibling)
if (dn->devfn == devfn)
return rtas_read_config(dn, where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
} }
#define RTAS_PCI_WRITE_OP(size, type, nbytes) \ static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
int \ {
rtas_write_config_##size(struct device_node *dn, int offset, type val) { \ unsigned long buid, addr;
unsigned long buid; \ int ret;
unsigned int addr; \
int ret; \ if (!dn)
\ return -2;
if (dn == NULL) { \
ret = -2; \ addr = (dn->busno << 16) | (dn->devfn << 8) | where;
} else { \ buid = dn->phb->buid;
buid = dn->phb->buid; \ if (buid) {
addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \ ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
if (buid) { \ } else {
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \ ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val);
} else { \ }
ret = rtas_call(write_pci_config, 3, 1, NULL, addr, nbytes, (ulong)val); \ return ret;
} \
} \
return ret; \
} \
int \
rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \
struct device_node* dn = pci_device_to_OF_node(dev); \
int ret = rtas_write_config_##size(dn, offset, val); \
/* udbg_printf("write bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
} }
RTAS_PCI_READ_OP(byte, u8 *, 1) static int rtas_pci_write_config(struct pci_bus *bus,
RTAS_PCI_READ_OP(word, u16 *, 2) unsigned int devfn,
RTAS_PCI_READ_OP(dword, u32 *, 4) int where, int size, u32 val)
RTAS_PCI_WRITE_OP(byte, u8, 1) {
RTAS_PCI_WRITE_OP(word, u16, 2) struct device_node *busdn, *dn;
RTAS_PCI_WRITE_OP(dword, u32, 4)
if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
else
busdn = bus->sysdata; /* must be a phb */
/* Search only direct children of the bus */
for (dn = busdn->child; dn; dn = dn->sibling)
if (dn->devfn == devfn)
return rtas_write_config(dn, where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
struct pci_ops rtas_pci_ops = { struct pci_ops rtas_pci_ops = {
rtas_pci_read_config_byte, rtas_pci_read_config,
rtas_pci_read_config_word, rtas_pci_write_config
rtas_pci_read_config_dword,
rtas_pci_write_config_byte,
rtas_pci_write_config_word,
rtas_pci_write_config_dword,
}; };
/* /*
...@@ -563,7 +563,7 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ...@@ -563,7 +563,7 @@ alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words)
buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len); buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
if (buid_vals == NULL) { if (buid_vals == NULL) {
phb->buid = 0; phb->buid = 0;
} else { } else {
struct pci_bus check; struct pci_bus check;
...@@ -651,6 +651,11 @@ fixup_resources(struct pci_dev *dev) ...@@ -651,6 +651,11 @@ fixup_resources(struct pci_dev *dev)
if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) { if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) {
continue; continue;
} }
if (dev->resource[i].start > dev->resource[i].end) {
/* Bogus resource. Just clear it out. */
dev->resource[i].start = dev->resource[i].end = 0;
continue;
}
if (dev->resource[i].flags & IORESOURCE_IO) { if (dev->resource[i].flags & IORESOURCE_IO) {
if (is_eeh_implemented()) { if (is_eeh_implemented()) {
...@@ -776,14 +781,9 @@ pSeries_pcibios_init(void) ...@@ -776,14 +781,9 @@ pSeries_pcibios_init(void)
void void
pSeries_pcibios_init_early(void) pSeries_pcibios_init_early(void)
{ {
ppc_md.pcibios_read_config_byte = rtas_read_config_byte; ppc_md.pcibios_read_config = rtas_read_config;
ppc_md.pcibios_read_config_word = rtas_read_config_word; ppc_md.pcibios_write_config = rtas_write_config;
ppc_md.pcibios_read_config_dword = rtas_read_config_dword;
ppc_md.pcibios_write_config_byte = rtas_write_config_byte;
ppc_md.pcibios_write_config_word = rtas_write_config_word;
ppc_md.pcibios_write_config_dword = rtas_write_config_dword;
} }
/************************************************************************/ /************************************************************************/
/* Get a char* of the device physical location(U0.3-P1-I8) */ /* Get a char* of the device physical location(U0.3-P1-I8) */
/* See the Product Topology in the RS/6000 Architecture. */ /* See the Product Topology in the RS/6000 Architecture. */
......
...@@ -708,10 +708,10 @@ void create_tce_tables_for_busesLP(struct list_head *bus_list) ...@@ -708,10 +708,10 @@ void create_tce_tables_for_busesLP(struct list_head *bus_list)
*/ */
dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0); dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0);
if (dma_window) { if (dma_window) {
/* Busno hasn't been copied yet. /* Bussubno hasn't been copied yet.
* Do it now because getTceTableParmsPSeriesLP needs it. * Do it now because getTceTableParmsPSeriesLP needs it.
*/ */
busdn->busno = bus->number; busdn->bussubno = bus->number;
create_pci_bus_tce_table((unsigned long)busdn); create_pci_bus_tce_table((unsigned long)busdn);
} else } else
create_tce_tables_for_busesLP(&bus->children); create_tce_tables_for_busesLP(&bus->children);
...@@ -966,12 +966,12 @@ static void getTceTableParmsPSeriesLP(struct pci_controller *phb, ...@@ -966,12 +966,12 @@ static void getTceTableParmsPSeriesLP(struct pci_controller *phb,
panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name); panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name);
} }
newTceTable->busNumber = dn->busno; newTceTable->busNumber = dn->bussubno;
newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT; newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12); newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12);
newTceTable->base = 0; newTceTable->base = 0;
newTceTable->index = dma_window[0]; newTceTable->index = dma_window[0];
PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->busno); PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->bussubno);
PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name); PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name);
PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index = 0x%lx\n", newTceTable->index); PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index = 0x%lx\n", newTceTable->index);
PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset); PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset);
...@@ -1121,7 +1121,7 @@ void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size ...@@ -1121,7 +1121,7 @@ void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size
/* Client asked for way to much space. This is checked later anyway */ /* Client asked for way to much space. This is checked later anyway */
/* It is easier to debug here for the drivers than in the tce tables.*/ /* It is easier to debug here for the drivers than in the tce tables.*/
if(order >= NUM_TCE_LEVELS) { if(order >= NUM_TCE_LEVELS) {
printk("PCI_DMA: pci_unmap_single size to large: 0x%lx \n",size); printk("PCI_DMA: pci_unmap_single 0x%lx size to large: 0x%lx \n",dma_handle,size);
return; return;
} }
...@@ -1377,10 +1377,11 @@ void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int ...@@ -1377,10 +1377,11 @@ void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int
PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n"); PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n");
PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms); PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms);
if ( direction == PCI_DMA_NONE ) if ( direction == PCI_DMA_NONE || nelms == 0 )
BUG(); BUG();
dma_start_page = sg->dma_address & PAGE_MASK; dma_start_page = sg->dma_address & PAGE_MASK;
dma_end_page = 0;
for ( i=nelms; i>0; --i ) { for ( i=nelms; i>0; --i ) {
unsigned k = i - 1; unsigned k = i - 1;
if ( sg[k].dma_length ) { if ( sg[k].dma_length ) {
...@@ -1396,6 +1397,7 @@ void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int ...@@ -1396,6 +1397,7 @@ void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int
/* Client asked for way to much space. This is checked later anyway */ /* Client asked for way to much space. This is checked later anyway */
/* It is easier to debug here for the drivers than in the tce tables.*/ /* It is easier to debug here for the drivers than in the tce tables.*/
if(order >= NUM_TCE_LEVELS) { if(order >= NUM_TCE_LEVELS) {
printk("PCI_DMA: dma_start_page:0x%lx dma_end_page:0x%lx\n",dma_start_page,dma_end_page);
printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT)); printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
return; return;
} }
......
...@@ -74,9 +74,6 @@ update_dn_pci_info(struct device_node *dn, void *data) ...@@ -74,9 +74,6 @@ update_dn_pci_info(struct device_node *dn, void *data)
static void * __init static void * __init
write_OF_bars(struct device_node *dn, void *data) write_OF_bars(struct device_node *dn, void *data)
{ {
int i;
u32 oldbar, newbar, newbartest;
u8 config_offset;
char *name = get_property(dn, "name", 0); char *name = get_property(dn, "name", 0);
char *device_type = get_property(dn, "device_type", 0); char *device_type = get_property(dn, "device_type", 0);
char devname[128]; char devname[128];
...@@ -95,21 +92,25 @@ write_OF_bars(struct device_node *dn, void *data) ...@@ -95,21 +92,25 @@ write_OF_bars(struct device_node *dn, void *data)
return NULL; return NULL;
} }
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
int i;
u32 oldbar, newbar, newbartest;
u8 config_offset;
for (i = 0; i < dn->n_addrs; i++) { for (i = 0; i < dn->n_addrs; i++) {
newbar = dn->addrs[i].address; newbar = dn->addrs[i].address;
config_offset = dn->addrs[i].space & 0xff; config_offset = dn->addrs[i].space & 0xff;
if (ppc_md.pcibios_read_config_dword(dn, config_offset, &oldbar) != PCIBIOS_SUCCESSFUL) { if (ppc_md.pcibios_read_config(dn, config_offset, 4, &oldbar) != PCIBIOS_SUCCESSFUL) {
printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i); printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i);
continue; continue;
} }
/* Need to update this BAR. */ /* Need to update this BAR. */
if (ppc_md.pcibios_write_config_dword(dn, config_offset, newbar) != PCIBIOS_SUCCESSFUL) { if (ppc_md.pcibios_write_config(dn, config_offset, 4, newbar) != PCIBIOS_SUCCESSFUL) {
printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar); printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar);
continue; continue;
} }
/* sanity check */ /* sanity check */
if (ppc_md.pcibios_read_config_dword(dn, config_offset, &newbartest) != PCIBIOS_SUCCESSFUL) { if (ppc_md.pcibios_read_config(dn, config_offset, 4, &newbartest) != PCIBIOS_SUCCESSFUL) {
printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i); printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i);
continue; continue;
} }
...@@ -214,7 +215,6 @@ void *traverse_all_pci_devices(traverse_func pre) ...@@ -214,7 +215,6 @@ void *traverse_all_pci_devices(traverse_func pre)
return NULL; return NULL;
} }
/* Traversal func that looks for a <busno,devfcn> value. /* Traversal func that looks for a <busno,devfcn> value.
* If found, the device_node is returned (thus terminating the traversal). * If found, the device_node is returned (thus terminating the traversal).
*/ */
...@@ -223,6 +223,7 @@ is_devfn_node(struct device_node *dn, void *data) ...@@ -223,6 +223,7 @@ is_devfn_node(struct device_node *dn, void *data)
{ {
int busno = ((unsigned long)data >> 8) & 0xff; int busno = ((unsigned long)data >> 8) & 0xff;
int devfn = ((unsigned long)data) & 0xff; int devfn = ((unsigned long)data) & 0xff;
return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL; return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
} }
......
...@@ -31,9 +31,6 @@ struct smp_ops_t { ...@@ -31,9 +31,6 @@ struct smp_ops_t {
#endif #endif
struct machdep_calls { struct machdep_calls {
/* High use functions in the first cachelines, low use functions
* follow. DRENG collect profile data.
*/
void (*hpte_invalidate)(unsigned long slot, void (*hpte_invalidate)(unsigned long slot,
unsigned long va, unsigned long va,
int large, int large,
...@@ -104,12 +101,8 @@ struct machdep_calls { ...@@ -104,12 +101,8 @@ struct machdep_calls {
int (*udbg_getc_poll)(void); int (*udbg_getc_poll)(void);
/* PCI interfaces */ /* PCI interfaces */
int (*pcibios_read_config_byte)(struct device_node *dn, int offset, u8 *val); int (*pcibios_read_config)(struct device_node *dn, int where, int size, u32 *val);
int (*pcibios_read_config_word)(struct device_node *dn, int offset, u16 *val); int (*pcibios_write_config)(struct device_node *dn, int where, int size, u32 val);
int (*pcibios_read_config_dword)(struct device_node *dn, int offset, u32 *val);
int (*pcibios_write_config_byte)(struct device_node *dn, int offset, u8 val);
int (*pcibios_write_config_word)(struct device_node *dn, int offset, u16 val);
int (*pcibios_write_config_dword)(struct device_node *dn, int offset, u32 val);
/* Called after scanning the bus, before allocating /* Called after scanning the bus, before allocating
* resources * resources
......
...@@ -126,6 +126,7 @@ struct device_node { ...@@ -126,6 +126,7 @@ struct device_node {
struct interrupt_info *intrs; struct interrupt_info *intrs;
char *full_name; char *full_name;
int busno; /* for pci devices */ int busno; /* for pci devices */
int bussubno; /* for pci devices */
int devfn; /* for pci devices */ int devfn; /* for pci devices */
struct pci_controller *phb; /* for pci devices */ struct pci_controller *phb; /* for pci devices */
struct TceTable *tce_table; /* for phb's or bridges */ struct TceTable *tce_table; /* for phb's or bridges */
......
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