diff --git a/Makefile b/Makefile diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 6274cd2..51a6384 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -36,6 +36,7 @@ #include #include #include +#include #include /* See comments in include/asm-parisc/pci.h */ @@ -306,9 +307,15 @@ static void get_node_path(struct device *dev, struct hardware_path *path) memset(&path->bc, -1, 6); if (is_pci_dev(dev)) { - unsigned int devfn = to_pci_dev(dev)->devfn; - path->mod = PCI_FUNC(devfn); - path->bc[i--] = PCI_SLOT(devfn); + struct pci_dev *pdev = to_pci_dev(dev); + if (is_pdc_pat()) { + int ret = pdc_pat_get_hwpath_from_pci( + pdc_address(pdev), path); + if (ret == PDC_OK) + return; + } + path->mod = PCI_FUNC(pdev->devfn); + path->bc[i--] = PCI_SLOT(pdev->devfn); dev = dev->parent; } @@ -318,6 +325,8 @@ static void get_node_path(struct device *dev, struct hardware_path *path) path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5); } else if (dev->bus == &parisc_bus_type) { path->bc[i--] = to_parisc_device(dev)->hw_path; + if (is_pdc_pat()) + path->flags = to_parisc_device(dev)->cell; } dev = dev->parent; } @@ -326,6 +335,10 @@ static void get_node_path(struct device *dev, struct hardware_path *path) static char *print_hwpath(struct hardware_path *path, char *output) { int i; + + if (is_pdc_pat()) + output += sprintf(output, "%u/", path->flags & HWP_CELL); + for (i = 0; i < 6; i++) { if (path->bc[i] == -1) continue; @@ -406,13 +419,15 @@ static void setup_bus_id(struct parisc_device *padev) sprintf(output, "%u", (unsigned char) padev->hw_path); } -struct parisc_device * create_tree_node(char id, struct device *parent) +static struct parisc_device * +create_tree_node(struct device *parent, char cell, char id) { struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; dev->hw_path = id; + dev->cell = cell; dev->id.hw_type = HPHW_FAULTY; dev->dev.parent = parent; @@ -434,6 +449,7 @@ struct parisc_device * create_tree_node(char id, struct device *parent) struct match_id_data { char id; + char cell; struct parisc_device * dev; }; @@ -442,7 +458,7 @@ static int match_by_id(struct device * dev, void * data) struct parisc_device * pdev = to_parisc_device(dev); struct match_id_data * d = data; - if (pdev->hw_path == d->id) { + if (pdev->hw_path == d->id && pdev->cell == d->cell) { d->dev = pdev; return 1; } @@ -457,27 +473,29 @@ static int match_by_id(struct device * dev, void * data) * Checks all the children of @parent for a matching @id. If none * found, it allocates a new device and returns it. */ -static struct parisc_device * alloc_tree_node(struct device *parent, char id) +static struct parisc_device * alloc_tree_node(struct device *parent, char cell, char id) { struct match_id_data d = { .id = id, + .cell = cell, }; if (device_for_each_child(parent, &d, match_by_id)) return d.dev; else - return create_tree_node(id, parent); + return create_tree_node(parent, cell, id); } static struct parisc_device *create_parisc_device(struct hardware_path *modpath) { int i; + char cell = is_pdc_pat() ? modpath->flags & HWP_CELL : 0; struct device *parent = &root; for (i = 0; i < 6; i++) { if (modpath->bc[i] == -1) continue; - parent = &alloc_tree_node(parent, modpath->bc[i])->dev; + parent = &alloc_tree_node(parent, cell, modpath->bc[i])->dev; } - return alloc_tree_node(parent, modpath->mod); + return alloc_tree_node(parent, cell, modpath->mod); } struct parisc_device * diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 9158b70..7516790 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -1387,6 +1387,20 @@ int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val) return retval; } + +int pdc_pat_get_hwpath_from_pci(unsigned long pci_addr, struct hardware_path *path) +{ + int retval; + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); + retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_HW_FROM_PCI_CONFIG, + __pa(pdc_result), pci_addr); + memcpy(path, pdc_result, 8); + spin_unlock_irqrestore(&pdc_lock, flags); + + return retval; +} #endif /* __LP64__ */ diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index ea1b7a6..66afab8 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -67,6 +67,7 @@ #include #include +#include #include #include #include @@ -541,7 +542,7 @@ pdcs_size_read(struct subsystem *entry, char *buf) * pdcs_auto_read - Stable Storage autoboot/search flag output. * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. - * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag + * @knob: The HWP_AUTOBOOT or HWP_AUTOSEARCH flag */ static ssize_t pdcs_auto_read(struct subsystem *entry, char *buf, int knob) @@ -571,7 +572,7 @@ pdcs_auto_read(struct subsystem *entry, char *buf, int knob) static inline ssize_t pdcs_autoboot_read(struct subsystem *entry, char *buf) { - return pdcs_auto_read(entry, buf, PF_AUTOBOOT); + return pdcs_auto_read(entry, buf, HWP_AUTOBOOT); } /** @@ -582,7 +583,7 @@ pdcs_autoboot_read(struct subsystem *entry, char *buf) static inline ssize_t pdcs_autosearch_read(struct subsystem *entry, char *buf) { - return pdcs_auto_read(entry, buf, PF_AUTOSEARCH); + return pdcs_auto_read(entry, buf, HWP_AUTOSEARCH); } /** @@ -597,19 +598,28 @@ pdcs_timer_read(struct subsystem *entry, char *buf) { char *out = buf; struct pdcspath_entry *pathentry; + int timer; if (!entry || !buf) return -EINVAL; + /* + * PDC PAT machines use the timer field for something different. + * I don't know where they keep the timer field now ... + */ + if (is_pdc_pat()) + return -ENODEV; + /* Current flags are stored in primary boot path entry */ pathentry = &pdcspath_entry_primary; - /* print the timer value in seconds */ read_lock(&pathentry->rw_lock); - out += sprintf(out, "%u\n", (pathentry->devpath.flags & PF_TIMER) ? - (1 << (pathentry->devpath.flags & PF_TIMER)) : 0); + timer = pathentry->devpath.flags & HWP_TIMER; read_unlock(&pathentry->rw_lock); + /* print the timer value in seconds */ + out += sprintf(out, "%u\n", timer ? (1 << timer) : 0); + return out - buf; } @@ -751,7 +761,7 @@ pdcs_osdep2_read(struct subsystem *entry, char *buf) * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. - * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag + * @knob: The HWP_AUTOBOOT or HWP_AUTOSEARCH flag * * We will call this function to change the current autoboot flag. * We expect a precise syntax: @@ -811,7 +821,7 @@ pdcs_auto_write(struct subsystem *entry, const char *buf, size_t count, int knob write_unlock(&pathentry->rw_lock); printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n", - (knob & PF_AUTOBOOT) ? "autoboot" : "autosearch", + (knob & HWP_AUTOBOOT) ? "autoboot" : "autosearch", (flags & knob) ? "On" : "Off"); return count; @@ -834,7 +844,7 @@ parse_error: static inline ssize_t pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count) { - return pdcs_auto_write(entry, buf, count, PF_AUTOBOOT); + return pdcs_auto_write(entry, buf, count, HWP_AUTOBOOT); } /** @@ -850,7 +860,7 @@ pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count) static inline ssize_t pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count) { - return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH); + return pdcs_auto_write(entry, buf, count, HWP_AUTOSEARCH); } /** diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h index e12624d..feb1861 100644 --- a/include/asm-parisc/parisc-device.h +++ b/include/asm-parisc/parisc-device.h @@ -12,6 +12,7 @@ struct parisc_device { int aux_irq; /* Some devices have a second IRQ */ char hw_path; /* The module number on this bus */ + char cell; /* Only on PAT machines */ unsigned int num_addrs; /* some devices have additional address ranges. */ unsigned long *addr; /* which will be stored here */ diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 423c2b8..7f8f4ef 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -561,9 +561,10 @@ struct pdc_hpmc_pim_20 { /* PDC_PIM */ #endif /* __ASSEMBLY__ */ /* flags of the device_path (see below) */ -#define PF_AUTOBOOT 0x80 -#define PF_AUTOSEARCH 0x40 -#define PF_TIMER 0x0F +#define HWP_AUTOBOOT 0x80 +#define HWP_AUTOSEARCH 0x40 +#define HWP_CELL 0x3F /* On PAT systems */ +#define HWP_TIMER 0x0F /* Non-PAT systems */ #ifndef __ASSEMBLY__ diff --git a/include/asm-parisc/pdcpat.h b/include/asm-parisc/pdcpat.h index 47539f1..35882d8 100644 --- a/include/asm-parisc/pdcpat.h +++ b/include/asm-parisc/pdcpat.h @@ -192,15 +192,20 @@ #ifdef CONFIG_64BIT #define is_pdc_pat() (PDC_TYPE_PAT == pdc_type) -extern int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num); +extern int pdc_pat_get_irt_size(unsigned long *num_entries, + unsigned long cell_num); extern int pdc_pat_get_irt(void *r_addr, unsigned long cell_num); +extern int pdc_pat_get_hwpath_from_pci(unsigned long address, + struct hardware_path *path); #else /* ! CONFIG_64BIT */ /* No PAT support for 32-bit kernels...sorry */ #define is_pdc_pat() (0) #define pdc_pat_get_irt_size(num_entries, cell_numn) PDC_BAD_PROC #define pdc_pat_get_irt(r_addr, cell_num) PDC_BAD_PROC +#define pdc_pat_get_hwpath_from_pci(address, path) PDC_BAD_PROC #endif /* ! CONFIG_64BIT */ +#define pdc_address(dev) (dev->bus->number << 16) | (dev->devfn << 8) struct pdc_pat_cell_num { unsigned long cell_num;