Staging: ipack/bridges/tpci200: Use the TPCI200 in big endian mode.
authorJens Taprogge <jens.taprogge@taprogge.org>
Tue, 4 Sep 2012 15:01:07 +0000 (17:01 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Sep 2012 21:39:54 +0000 (14:39 -0700)
During initialization we configure the TPCI200 so it does not swap data
lanes on IndustryPack module access.  The read and write functions are
changed accordingly.

We are taking this approach in the hope that all IP Carriers are able to
present the Module memory layout unchanged.  We can thus directly access
the memory and registers of IP Modules without having to rely on the
read and write wrappers currently exposed in ipack_bus_opts.  A later
patch will convert the existing driver and remove the wrappers.

Signed-off-by: Jens Taprogge <jens.taprogge@taprogge.org>
Signed-off-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/ipack/bridges/tpci200.c
drivers/staging/ipack/bridges/tpci200.h
drivers/staging/ipack/devices/ipoctal.c

index eda02e7..f2501c9 100644 (file)
@@ -54,39 +54,39 @@ static struct tpci200_board *check_slot(struct ipack_device *dev)
 static inline unsigned char __tpci200_read8(void __iomem *address,
                                            unsigned long offset)
 {
-       return ioread8(address + (offset^1));
+       return ioread8(address + offset);
 }
 
 static inline unsigned short __tpci200_read16(void __iomem *address,
                                              unsigned long offset)
 {
-       return ioread16(address + offset);
+       return ioread16be(address + offset);
 }
 
 static inline unsigned int __tpci200_read32(void __iomem *address,
                                            unsigned long offset)
 {
-       return swahw32(ioread32(address + offset));
+       return ioread32be(address + offset);
 }
 
 static inline void __tpci200_write8(unsigned char value,
                                    void __iomem *address, unsigned long offset)
 {
-       iowrite8(value, address+(offset^1));
+       iowrite8(value, address + offset);
 }
 
 static inline void __tpci200_write16(unsigned short value,
                                     void __iomem *address,
                                     unsigned long offset)
 {
-       iowrite16(value, address+offset);
+       iowrite16be(value, address + offset);
 }
 
 static inline void __tpci200_write32(unsigned int value,
                                     void __iomem *address,
                                     unsigned long offset)
 {
-       iowrite32(swahw32(value), address+offset);
+       iowrite32be(value, address + offset);
 }
 
 static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
@@ -783,6 +783,7 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 {
        int ret, i;
        struct tpci200_board *tpci200;
+       __le32 reg32;
 
        tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
        if (!tpci200)
@@ -794,6 +795,34 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
                goto out_err_info;
        }
 
+       /* Obtain a mapping of the carrier's PCI configuration registers */
+       ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR,
+                                KBUILD_MODNAME " Configuration Memory");
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
+               ret = -EBUSY;
+               goto out_err_pci_request;
+       }
+       tpci200->info->cfg_regs = ioremap_nocache(
+                       pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
+                       pci_resource_len(pdev, TPCI200_CFG_MEM_BAR));
+       if (!tpci200->info->cfg_regs) {
+               dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
+               ret = -EFAULT;
+               goto out_err_ioremap;
+       }
+
+       /* Disable byte swapping for 16 bit IP module access. This will ensure
+        * that the Industrypack big endian byte order is preserved by the
+        * carrier. */
+       reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC);
+       reg32 |= 1 << LAS_BIT_BIGENDIAN;
+       iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC);
+
+       reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC);
+       reg32 |= 1 << LAS_BIT_BIGENDIAN;
+       iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC);
+
        /* Save struct pci_dev pointer */
        tpci200->info->pdev = pdev;
        tpci200->info->id_table = (struct pci_device_id *)id;
@@ -833,6 +862,10 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 out_err_bus_register:
        tpci200_uninstall(tpci200);
 out_err_install:
+       iounmap(tpci200->info->cfg_regs);
+out_err_ioremap:
+       pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
+out_err_pci_request:
        kfree(tpci200->info);
 out_err_info:
        kfree(tpci200);
@@ -843,6 +876,10 @@ static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 {
        tpci200_uninstall(tpci200);
        ipack_bus_unregister(tpci200->info->ipack_bus);
+
+       iounmap(tpci200->info->cfg_regs);
+       pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
+
        kfree(tpci200->info);
        kfree(tpci200);
 }
index d04510a..38acba1 100644 (file)
@@ -31,6 +31,7 @@
 #define TPCI200_SUBVENDOR_ID          0x1498
 #define TPCI200_SUBDEVICE_ID          0x300A
 
+#define TPCI200_CFG_MEM_BAR           0
 #define TPCI200_IP_INTERFACE_BAR      2
 #define TPCI200_IO_ID_INT_SPACES_BAR  3
 #define TPCI200_MEM16_SPACE_BAR       4
 
 #define TPCI200_SLOT_INT_MASK         0x00FF
 
+/* PCI Configuration registers. The PCI bridge is a PLX Technology PCI9030. */
+#define LAS1_DESC                    0x2C
+#define LAS2_DESC                    0x30
+
+/* Bits in the LAS?_DESC registers */
+#define LAS_BIT_BIGENDIAN            24
+
 #define VME_IOID_SPACE  "IOID"
 #define VME_MEM_SPACE  "MEM"
 
@@ -144,6 +152,7 @@ struct tpci200_infos {
        void __iomem                    *interface_regs;
        void __iomem                    *ioidint_space;
        void __iomem                    *mem8_space;
+       void __iomem                    *cfg_regs;
        struct ipack_bus_device         *ipack_bus;
 };
 struct tpci200_board {
index fd0e301..963ed20 100644 (file)
@@ -449,7 +449,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
         */
        ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector,
                                       ipoctal_irq_handler, ipoctal);
-       ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_MEM_SPACE, 0,
+       ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_MEM_SPACE, 1,
                                       vector);
 
        /* Register the TTY device */