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;
static int s7a_workaround;
/******************************************************************************
*
* pSeries I/O Operations to access the PCI configuration space.
*
*****************************************************************************/
#define RTAS_PCI_READ_OP(size, type, nbytes) \
int \
rtas_read_config_##size(struct device_node *dn, int offset, type val) { \
unsigned long returnval = ~0L; \
unsigned long buid; \
unsigned int addr; \
int ret; \
\
if (dn == NULL) { \
ret = -2; \
} else { \
addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
buid = dn->phb->buid; \
if (buid) { \
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
if (ret < 0|| (returnval == 0xffffffff)) \
ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
} else { \
ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \
} \
} \
*val = returnval; \
return ret; \
} \
int \
rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) { \
struct device_node *dn = pci_device_to_OF_node(dev); \
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); */ \
return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
{
unsigned long returnval = ~0L;
unsigned long buid, addr;
int ret;
if (!dn)
return -2;
addr = (dn->busno << 16) | (dn->devfn << 8) | where;
buid = dn->phb->buid;
if (buid) {
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, size);
if (ret < 0|| (returnval == 0xffffffff))
ret = rtas_fake_read(dn, where, size, &returnval);
} else {
ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
}
*val = returnval;
return ret;
}
static int rtas_pci_read_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 *val)
{
struct device_node *busdn, *dn;
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_read_config(dn, where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
#define RTAS_PCI_WRITE_OP(size, type, nbytes) \
int \
rtas_write_config_##size(struct device_node *dn, int offset, type val) { \
unsigned long buid; \
unsigned int addr; \
int ret; \
\
if (dn == NULL) { \
ret = -2; \
} else { \
buid = dn->phb->buid; \
addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
if (buid) { \
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \
} else { \
ret = rtas_call(write_pci_config, 3, 1, NULL, addr, nbytes, (ulong)val); \
} \
} \
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; \
static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
{
unsigned long buid, addr;
int ret;
if (!dn)
return -2;
addr = (dn->busno << 16) | (dn->devfn << 8) | where;
buid = dn->phb->buid;
if (buid) {
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
} else {
ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val);
}
return ret;
}
RTAS_PCI_READ_OP(byte, u8 *, 1)
RTAS_PCI_READ_OP(word, u16 *, 2)
RTAS_PCI_READ_OP(dword, u32 *, 4)
RTAS_PCI_WRITE_OP(byte, u8, 1)
RTAS_PCI_WRITE_OP(word, u16, 2)
RTAS_PCI_WRITE_OP(dword, u32, 4)
static int rtas_pci_write_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 val)
{
struct device_node *busdn, *dn;
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 = {
rtas_pci_read_config_byte,
rtas_pci_read_config_word,
rtas_pci_read_config_dword,
rtas_pci_write_config_byte,
rtas_pci_write_config_word,
rtas_pci_write_config_dword,
rtas_pci_read_config,
rtas_pci_write_config
};
/*
......@@ -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);
if (buid_vals == NULL) {
if (buid_vals == NULL) {
phb->buid = 0;
} else {
struct pci_bus check;
......@@ -651,6 +651,11 @@ fixup_resources(struct pci_dev *dev)
if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) {
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 (is_eeh_implemented()) {
......@@ -776,14 +781,9 @@ pSeries_pcibios_init(void)
void
pSeries_pcibios_init_early(void)
{
ppc_md.pcibios_read_config_byte = rtas_read_config_byte;
ppc_md.pcibios_read_config_word = rtas_read_config_word;
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;
ppc_md.pcibios_read_config = rtas_read_config;
ppc_md.pcibios_write_config = rtas_write_config;
}
/************************************************************************/
/* Get a char* of the device physical location(U0.3-P1-I8) */
/* See the Product Topology in the RS/6000 Architecture. */
......
......@@ -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);
if (dma_window) {
/* Busno hasn't been copied yet.
/* Bussubno hasn't been copied yet.
* Do it now because getTceTableParmsPSeriesLP needs it.
*/
busdn->busno = bus->number;
busdn->bussubno = bus->number;
create_pci_bus_tce_table((unsigned long)busdn);
} else
create_tce_tables_for_busesLP(&bus->children);
......@@ -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);
}
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->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12);
newTceTable->base = 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, "\tnewTceTable->index = 0x%lx\n", newTceTable->index);
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
/* 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.*/
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;
}
......@@ -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, "\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();
dma_start_page = sg->dma_address & PAGE_MASK;
dma_end_page = 0;
for ( i=nelms; i>0; --i ) {
unsigned k = i - 1;
if ( sg[k].dma_length ) {
......@@ -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 */
/* It is easier to debug here for the drivers than in the tce tables.*/
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));
return;
}
......
......@@ -74,9 +74,6 @@ update_dn_pci_info(struct device_node *dn, void *data)
static void * __init
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 *device_type = get_property(dn, "device_type", 0);
char devname[128];
......@@ -95,21 +92,25 @@ write_OF_bars(struct device_node *dn, void *data)
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++) {
newbar = dn->addrs[i].address;
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);
continue;
}
/* 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);
continue;
}
/* 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);
continue;
}
......@@ -214,7 +215,6 @@ void *traverse_all_pci_devices(traverse_func pre)
return NULL;
}
/* Traversal func that looks for a <busno,devfcn> value.
* If found, the device_node is returned (thus terminating the traversal).
*/
......@@ -223,6 +223,7 @@ is_devfn_node(struct device_node *dn, void *data)
{
int busno = ((unsigned long)data >> 8) & 0xff;
int devfn = ((unsigned long)data) & 0xff;
return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
}
......
......@@ -31,9 +31,6 @@ struct smp_ops_t {
#endif
struct machdep_calls {
/* High use functions in the first cachelines, low use functions
* follow. DRENG collect profile data.
*/
void (*hpte_invalidate)(unsigned long slot,
unsigned long va,
int large,
......@@ -104,12 +101,8 @@ struct machdep_calls {
int (*udbg_getc_poll)(void);
/* PCI interfaces */
int (*pcibios_read_config_byte)(struct device_node *dn, int offset, u8 *val);
int (*pcibios_read_config_word)(struct device_node *dn, int offset, u16 *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);
int (*pcibios_read_config)(struct device_node *dn, int where, int size, u32 *val);
int (*pcibios_write_config)(struct device_node *dn, int where, int size, u32 val);
/* Called after scanning the bus, before allocating
* resources
......
......@@ -126,6 +126,7 @@ struct device_node {
struct interrupt_info *intrs;
char *full_name;
int busno; /* for pci devices */
int bussubno; /* for pci devices */
int devfn; /* for pci devices */
struct pci_controller *phb; /* for pci devices */
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