[parisc-linux] Using PAT_IO calls for PCI config space reads and writes.

Naresh Kumar knaresh at india.hp.com
Tue Jan 27 01:39:38 MST 2004


Hi all,

When I was trying to bring up PA-Linux-2.4 on some of the newer boxes, I
discovered that reads/writes from the PCI config space were failing (
system crashes and hangs during the boot). Currently, reads and writes
to the config space happen through memory loads and stores to PCI config
addresses directly  (lba_cfg_[read|write]##size in lba_pci.c ). Grant
Grundler advised me to use PDC_PAT_IO calls instead, for PAT based
systems, since they are more reliable and take care of border cases on
newer systems. I have made the changes and tested them on an L-Class
system. I am posting the diff of the files I have changed. The changes
have been made to three files:

1. arch/parisc/kernel/firmware.c - Rev 1.47
2. arch/parisc/kernel/lba_pci.c - Rev 1.54
3. include/asm-parisc/pdc.h - Rev 1.48

Kindly let me know your comments:

--------------------START------------------------------------------------------------------------------

--- lba_pci.c.1.54       Fri Jan 23 15:47:41 2004
+++ lba_pci.c.modified   Fri Jan 23 15:53:15 2004
@@ -504,6 +504,13 @@ lba_rd_cfg(struct lba_device *d, u32 tok
        return(data);
 }

+#ifdef __LP64__
+#define PAT_CFG_READ(a,b,c)    pdc_pat_io_pci_cfg_read(a,b,c)
+#define PAT_CFG_WRITE(a,b,c)   pdc_pat_io_pci_cfg_write(a,b,c)
+#else
+#define PAT_CFG_READ(a,b,c)
+#define PAT_CFG_WRITE(a,b,c)
+#endif

 #define LBA_CFG_RD(size, mask) \
 static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size
*data) \
@@ -512,6 +519,21 @@ static int lba_cfg_read##size (struct pc
        u32 local_bus = (dev->bus->parent == NULL) ? 0 :
dev->bus->secondary; \
        u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
  \
+       if (is_pdc_pat()) { \
+               int ret; \
+               tok = LBA_CFG_TOK(dev->bus->number,dev->devfn); \
+               ret = PAT_CFG_READ((tok | pos ), \
+                                        sizeof(u##size), (u##size *)
data); \
+               if ( ret == 0 ) { \
+                       DBG_CFG("%s(%s+%2x) -> 0x%x (c)\n",
__FUNCTION__, dev->slot_name, pos, *data
); \
+                       return(*data == (u##size) -1); \
+               } else { \
+                       DBG_CFG("LBA: CFG read failed: ret = %d,
d->hba.base_addr = 0x%lx\n", \
+                                               ret, d->hba.base_addr );
\
+                       return (1); \
+               } \
+       } \
+ \
 /* FIXME: B2K/C3600 workaround is always use old method... */ \
        /* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ { \
                /* original - Generate config cycle on broken elroy \
@@ -611,6 +633,11 @@ static int lba_cfg_write##size (struct p
        } \
  \
        DBG_CFG("%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name,
pos, data); \
+       if (is_pdc_pat()) { \
+               tok = LBA_CFG_TOK(dev->bus->number,dev->devfn); \
+               PAT_CFG_WRITE((tok | pos ), sizeof(u##size), (u##size
*)&data); \
+               return 0; \
+       } \
        /* Basic Algorithm */ \
        LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
        WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos
& mask)); \
-------------------------------------END---------------------------------------------------------------

------------------------------------START-------------------------------------------------------------

--- firmware.c.1.47      Fri Jan 23 16:57:51 2004
+++ firmware.c.modified   Tue Jan 27 12:32:43 2004
@@ -1035,6 +1035,46 @@ int pdc_pat_pd_get_addr_map(unsigned lon

        return retval;
 }
+
+/**
+ * pdc_pat_io_pci_cfg_read - Read PCI configuration space.
+ * @pci_addr: PCI configuration space address for which the read
request is being made.
+ * @pci_size: Size of read in bytes. Valid values are 1, 2, and 4.
+ * @mem_addr: Pointer to return memory buffer.
+ *
+ */
+int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, void
*mem_addr)
+{
+       int retval;
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ,
__pa(pdc_result),
+                             pci_addr, pci_size);
+       memcpy((char *)mem_addr, (char *) ((char *)pdc_result +
(sizeof(unsigned long) - pci_size))
, pci_size);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_io_pci_cfg_write - Retrieve information about memory address
ranges.
+ * @pci_addr: PCI configuration space address for which the write
request is being made.
+ * @pci_size: Size of write in bytes. Valid values are 1, 2, and 4.
+ * @value: Pointer to 1, 2, or 4 byte value in low order end of
argument to be
+ *         written to PCI Config space.
+ *
+ */
+int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, void
*value)
+{
+       int retval;
+       unsigned long *val_ptr;
+       spin_lock_irq(&pdc_lock);
+       memcpy((char *)((char *)val_ptr + (sizeof(unsigned long) -
pci_size)), (char *)value, pci_si
ze);
+       retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_WRITE,
pci_addr,
+                             pci_size, *val_ptr);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
 #endif /* __LP64__ */
-------------------------------------END---------------------------------------------------------------

------------------------------------START-------------------------------------------------------------

--- pdc.h.1.48   Fri Jan 23 16:57:52 2004
+++ pdc.h.modified        Fri Jan 23 12:21:46 2004
@@ -972,6 +972,8 @@ int pdc_pat_get_irt_size(unsigned long *
 int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
 int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
                            unsigned long count, unsigned long offset);
+int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, void
*mem_addr);
+int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, void
*value);

 /******************************************************************** *

 *PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
-------------------------------------END---------------------------------------------------------------

A couple of questions:
1. In the definition of 'pdc_pat_io_pci_cfg_read( )' and
'pdc_pat_io_pci_cfg_write( )' above, can I  use 'cpu_to_le64( )' kind of
function instead of ordering the bytes manually in the 'memcpy( )'?
2. Can these changes be propagated to 2.6 also?

Thanks,
Naresh.



More information about the parisc-linux mailing list