From patchwork Tue Jul 13 02:01:17 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Chagas X-Patchwork-Id: 111578 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6D21Uv1010813 for ; Tue, 13 Jul 2010 02:01:35 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756239Ab0GMCBT (ORCPT ); Mon, 12 Jul 2010 22:01:19 -0400 Received: from mail-iw0-f174.google.com ([209.85.214.174]:45736 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756238Ab0GMCBS convert rfc822-to-8bit (ORCPT ); Mon, 12 Jul 2010 22:01:18 -0400 Received: by iwn7 with SMTP id 7so5299879iwn.19 for ; Mon, 12 Jul 2010 19:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:date:message-id :subject:from:to:content-type:content-transfer-encoding; bh=APx0+n8RhevYLtZmbQEkPXRPTkGMumpGFU1jZ0w2sZ4=; b=KGUfIQ2k8kaQSFAh/NrO31QzIcTHVq402sD0iuDmQ7N6GMWSADC8LBK4V19QOto5FY GrwuIobacqn+pegadbEhyC1UjQZOm/RWDLI3PdCD7KeK7YiKjqIOrrbg0gI4JRipasuo KQ3vx4jGzN5A8FI7JM1TQS2Ph8aBFP41RCEao= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type :content-transfer-encoding; b=Ro4JifGr5oaMCrieJFV3eU8N6381cICXxdwHZYuuNiNzesL7xAjNGqdN3OjJTD7P+P bYYZl1aLG0vuA9z/dX9KfG6TlypfPp9d4+SZoJS/NzlH//L6zKtTL0WAfkS4sZQ3GEhS IH1U8SypWFWaI2PVYherBZTiAP+WOC+FV/OXw= MIME-Version: 1.0 Received: by 10.231.150.15 with SMTP id w15mr14818229ibv.115.1278986477285; Mon, 12 Jul 2010 19:01:17 -0700 (PDT) Received: by 10.231.37.7 with HTTP; Mon, 12 Jul 2010 19:01:17 -0700 (PDT) Date: Mon, 12 Jul 2010 22:01:17 -0400 Message-ID: Subject: RFC: extending struct pci_ops to include HW specific read and write functions From: Jason Chagas To: linux-pci@vger.kernel.org Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 13 Jul 2010 02:01:35 +0000 (UTC) =========== diff --git a/include/linux/pci.h b/include/linux/pci.h index 7cb0084..0ba739a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -467,6 +467,15 @@ static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { return false; struct pci_ops { int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); + u8 (*hw_readb)(u32 addr); + u16 (*hw_readw)(u32 addr); + u32 (*hw_readl)(u32 addr); + void (*hw_writeb)(u8 val, u32 addr); + void (*hw_writew)(u16 val, u32 addr); + void (*hw_writel)(u32 val, u32 addr); + void (*hw_memcpy_fromio)(void *to, const volatile void __iomem *from, size_t count); + void (*hw_memcpy_toio)(volatile void __iomem *to, const void *from, size_t count); + void (*hw_memset_io)(volatile void __iomem *dst, int c, size_t count); }; /* =========== This provides a hardware independent interface to access devices on PCIe controllers that do not allow mapping PCIe memory onto CPU memory space. For instance, unlike standard designs where the driver maps PCI memory into virtual kernel space, the Marvell PXA168PXA PCIe controller does not allow mapping of PCIe memory to CPU memory space. It means that all driver data transfers must occur over DMA with phys addresses. For single byte/word/dword transactions, PXA168/PCIe provides a number of 'PIO' channels (4, actually). Such 'PIO' channels are, in turn, hw DMA interface abstractions for single 8/16/32bit access. Thus my proposal to extend 'struct pci_ops' with generic hw_read*()/hw_write*() functions that would abstract all the idiosyncrasies of accessing the 'PIO' interface. This would also provide an easy software migration path for future PCIe interface designs awhile still maintain backwards compatibility with existing software. Please refer to appended example of how the Yukon network driver (~/devices/net/sky2.c) would change to take advantage of these proposed extensions. Comments welcome! Thanks, Jason =================== EXAMPLE: diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 084eff2..3769e1c 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -4,6 +4,8 @@ #ifndef _SKY2_H #define _SKY2_H +#define __hw_mem_pci(a) ((u32)a) + #define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */ /* PCI config registers */ @@ -2301,32 +2303,70 @@ static inline int sky2_is_copper(const struct sky2_hw *hw) /* Register accessor for memory mapped device */ static inline u32 sky2_read32(const struct sky2_hw *hw, unsigned reg) { - return readl(hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + return (ops->hw_readl)?(ops->hw_readl(__hw_mem_pci(hw->regs + reg))): + (readl(hw->regs + reg)); } static inline u16 sky2_read16(const struct sky2_hw *hw, unsigned reg) { - return readw(hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + return (ops->hw_readw)?(ops->hw_readw(__hw_mem_pci(hw->regs + reg))): + (readw(hw->regs + reg)); } static inline u8 sky2_read8(const struct sky2_hw *hw, unsigned reg) { - return readb(hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + return (ops->hw_readb)?(ops->hw_readb(__hw_mem_pci(hw->regs + reg))): + (readb(hw->regs + reg)); } static inline void sky2_write32(const struct sky2_hw *hw, unsigned reg, u32 val) { - writel(val, hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + (ops->hw_writel)?(ops->hw_writel(val, __hw_mem_pci(hw->regs + reg))): + (writel(val, hw->regs + reg)); } static inline void sky2_write16(const struct sky2_hw *hw, unsigned reg, u16 val) { - writew(val, hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + (ops->hw_writew)?(ops->hw_writew(val, __hw_mem_pci(hw->regs + reg))): + (writew(val, hw->regs + reg)); } static inline void sky2_write8(const struct sky2_hw *hw, unsigned reg, u8 val) { - writeb(val, hw->regs + reg); + struct pci_ops *ops = hw->pdev->bus->ops; + + (ops->hw_writeb)?(ops->hw_writeb(val, __hw_mem_pci(hw->regs + reg))): + (writeb(val, hw->regs + reg)); +} + +static inline void +sky2_memcpy_fromio(const struct sky2_hw *hw, void *to, + const volatile void __iomem *from, size_t count) +{ + struct pci_ops *ops = hw->pdev->bus->ops; + + (ops->hw_memcpy_fromio)?(ops->hw_memcpy_fromio(to, from, count)): + (memcpy_fromio(to, from, count)); +} + +static inline void +sky2_memcpy_toio(const struct sky2_hw *hw, volatile void __iomem *to, + const void *from, size_t count) +{ + struct pci_ops *ops = hw->pdev->bus->ops; + + (ops->hw_memcpy_toio)?(ops->hw_memcpy_toio(to, from, count)): + (memcpy_toio(to, from, count)); } /* Yukon PHY related registers */ ====== diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7985165..2519693 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -152,6 +152,23 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 }; static void sky2_set_multicast(struct net_device *dev); +static void *sky2_map_regs_base(struct pci_dev *pdev) +{ +#if defined(CONFIG_PCI_NOCPU_PHYSICAL_MAPPING) + /* We shouldn't map an address that only the controller understands */ + return (void *) pci_resource_start(pdev, 0); +#else + return ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); +#endif +} + +static void sky2_unmap_regs_base(void *addr) +{ +#if !defined(CONFIG_PCI_NOCPU_PHYSICAL_MAPPING) + iounmap(addr); +#endif +} + /* Access to PHY via serial interconnect */ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)