diff options
| author | Steve Glendinning <steve.glendinning@smsc.com> | 2008-11-04 19:35:38 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-12-10 18:12:45 -0500 |
| commit | 2107fb8b5bf018be691afdd4c6ffaecf0c3307be (patch) | |
| tree | f3554a4cb46f23a9d4de7cc54d56ad229b055236 | |
| parent | 6fabd715e6d8e1b37c0c66d9bfda2c19643e3f77 (diff) | |
smsc911x: add dynamic bus configuration
Convert the driver to select 16-bit or 32-bit bus access at runtime,
at a small performance cost.
Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/smsc911x.c | 158 | ||||
| -rw-r--r-- | drivers/net/smsc911x.h | 1 | ||||
| -rw-r--r-- | include/linux/smsc911x.h | 5 |
3 files changed, 84 insertions, 80 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index fe517880fc97..4b8ff843e300 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c | |||
| @@ -77,19 +77,16 @@ struct smsc911x_data { | |||
| 77 | unsigned int generation; | 77 | unsigned int generation; |
| 78 | 78 | ||
| 79 | /* device configuration (copied from platform_data during probe) */ | 79 | /* device configuration (copied from platform_data during probe) */ |
| 80 | unsigned int irq_polarity; | 80 | struct smsc911x_platform_config config; |
| 81 | unsigned int irq_type; | ||
| 82 | phy_interface_t phy_interface; | ||
| 83 | 81 | ||
| 84 | /* This needs to be acquired before calling any of below: | 82 | /* This needs to be acquired before calling any of below: |
| 85 | * smsc911x_mac_read(), smsc911x_mac_write() | 83 | * smsc911x_mac_read(), smsc911x_mac_write() |
| 86 | */ | 84 | */ |
| 87 | spinlock_t mac_lock; | 85 | spinlock_t mac_lock; |
| 88 | 86 | ||
| 89 | #if (!SMSC_CAN_USE_32BIT) | 87 | /* spinlock to ensure 16-bit accesses are serialised. |
| 90 | /* spinlock to ensure 16-bit accesses are serialised */ | 88 | * unused with a 32-bit bus */ |
| 91 | spinlock_t dev_lock; | 89 | spinlock_t dev_lock; |
| 92 | #endif | ||
| 93 | 90 | ||
| 94 | struct phy_device *phy_dev; | 91 | struct phy_device *phy_dev; |
| 95 | struct mii_bus *mii_bus; | 92 | struct mii_bus *mii_bus; |
| @@ -121,70 +118,56 @@ struct smsc911x_data { | |||
| 121 | unsigned int hashlo; | 118 | unsigned int hashlo; |
| 122 | }; | 119 | }; |
| 123 | 120 | ||
| 124 | #if SMSC_CAN_USE_32BIT | 121 | /* The 16-bit access functions are significantly slower, due to the locking |
| 125 | |||
| 126 | static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) | ||
| 127 | { | ||
| 128 | return readl(pdata->ioaddr + reg); | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, | ||
| 132 | u32 val) | ||
| 133 | { | ||
| 134 | writel(val, pdata->ioaddr + reg); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* Writes a packet to the TX_DATA_FIFO */ | ||
| 138 | static inline void | ||
| 139 | smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, | ||
| 140 | unsigned int wordcount) | ||
| 141 | { | ||
| 142 | writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* Reads a packet out of the RX_DATA_FIFO */ | ||
| 146 | static inline void | ||
| 147 | smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, | ||
| 148 | unsigned int wordcount) | ||
| 149 | { | ||
| 150 | readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); | ||
| 151 | } | ||
| 152 | |||
| 153 | #else /* SMSC_CAN_USE_32BIT */ | ||
| 154 | |||
| 155 | /* These 16-bit access functions are significantly slower, due to the locking | ||
| 156 | * necessary. If your bus hardware can be configured to do this for you | 122 | * necessary. If your bus hardware can be configured to do this for you |
| 157 | * (in response to a single 32-bit operation from software), you should use | 123 | * (in response to a single 32-bit operation from software), you should use |
| 158 | * the 32-bit access functions instead. */ | 124 | * the 32-bit access functions instead. */ |
| 159 | 125 | ||
| 160 | static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) | 126 | static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) |
| 161 | { | 127 | { |
| 162 | unsigned long flags; | 128 | if (pdata->config.flags & SMSC911X_USE_32BIT) |
| 163 | u32 data; | 129 | return readl(pdata->ioaddr + reg); |
| 164 | 130 | ||
| 165 | /* these two 16-bit reads must be performed consecutively, so must | 131 | if (pdata->config.flags & SMSC911X_USE_16BIT) { |
| 166 | * not be interrupted by our own ISR (which would start another | 132 | u32 data; |
| 167 | * read operation) */ | 133 | unsigned long flags; |
| 168 | spin_lock_irqsave(&pdata->dev_lock, flags); | 134 | |
| 169 | data = ((readw(pdata->ioaddr + reg) & 0xFFFF) | | 135 | /* these two 16-bit reads must be performed consecutively, so |
| 170 | ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); | 136 | * must not be interrupted by our own ISR (which would start |
| 171 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 137 | * another read operation) */ |
| 138 | spin_lock_irqsave(&pdata->dev_lock, flags); | ||
| 139 | data = ((readw(pdata->ioaddr + reg) & 0xFFFF) | | ||
| 140 | ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); | ||
| 141 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | ||
| 142 | |||
| 143 | return data; | ||
| 144 | } | ||
| 172 | 145 | ||
| 173 | return data; | 146 | BUG(); |
| 174 | } | 147 | } |
| 175 | 148 | ||
| 176 | static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, | 149 | static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, |
| 177 | u32 val) | 150 | u32 val) |
| 178 | { | 151 | { |
| 179 | unsigned long flags; | 152 | if (pdata->config.flags & SMSC911X_USE_32BIT) { |
| 153 | writel(val, pdata->ioaddr + reg); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (pdata->config.flags & SMSC911X_USE_16BIT) { | ||
| 158 | unsigned long flags; | ||
| 159 | |||
| 160 | /* these two 16-bit writes must be performed consecutively, so | ||
| 161 | * must not be interrupted by our own ISR (which would start | ||
| 162 | * another read operation) */ | ||
| 163 | spin_lock_irqsave(&pdata->dev_lock, flags); | ||
| 164 | writew(val & 0xFFFF, pdata->ioaddr + reg); | ||
| 165 | writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); | ||
| 166 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | ||
| 167 | return; | ||
| 168 | } | ||
| 180 | 169 | ||
| 181 | /* these two 16-bit writes must be performed consecutively, so must | 170 | BUG(); |
| 182 | * not be interrupted by our own ISR (which would start another | ||
| 183 | * read operation) */ | ||
| 184 | spin_lock_irqsave(&pdata->dev_lock, flags); | ||
| 185 | writew(val & 0xFFFF, pdata->ioaddr + reg); | ||
| 186 | writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); | ||
| 187 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | ||
| 188 | } | 171 | } |
| 189 | 172 | ||
| 190 | /* Writes a packet to the TX_DATA_FIFO */ | 173 | /* Writes a packet to the TX_DATA_FIFO */ |
| @@ -192,8 +175,18 @@ static inline void | |||
| 192 | smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, | 175 | smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, |
| 193 | unsigned int wordcount) | 176 | unsigned int wordcount) |
| 194 | { | 177 | { |
| 195 | while (wordcount--) | 178 | if (pdata->config.flags & SMSC911X_USE_32BIT) { |
| 196 | smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); | 179 | writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); |
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (pdata->config.flags & SMSC911X_USE_16BIT) { | ||
| 184 | while (wordcount--) | ||
| 185 | smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); | ||
| 186 | return; | ||
| 187 | } | ||
| 188 | |||
| 189 | BUG(); | ||
| 197 | } | 190 | } |
| 198 | 191 | ||
| 199 | /* Reads a packet out of the RX_DATA_FIFO */ | 192 | /* Reads a packet out of the RX_DATA_FIFO */ |
| @@ -201,11 +194,19 @@ static inline void | |||
| 201 | smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, | 194 | smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, |
| 202 | unsigned int wordcount) | 195 | unsigned int wordcount) |
| 203 | { | 196 | { |
| 204 | while (wordcount--) | 197 | if (pdata->config.flags & SMSC911X_USE_32BIT) { |
| 205 | *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); | 198 | readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); |
| 206 | } | 199 | return; |
| 200 | } | ||
| 207 | 201 | ||
| 208 | #endif /* SMSC_CAN_USE_32BIT */ | 202 | if (pdata->config.flags & SMSC911X_USE_16BIT) { |
| 203 | while (wordcount--) | ||
| 204 | *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); | ||
| 205 | return; | ||
| 206 | } | ||
| 207 | |||
| 208 | BUG(); | ||
| 209 | } | ||
| 209 | 210 | ||
| 210 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read | 211 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read |
| 211 | * and smsc911x_mac_write, so assumes mac_lock is held */ | 212 | * and smsc911x_mac_write, so assumes mac_lock is held */ |
| @@ -790,7 +791,7 @@ static int smsc911x_mii_probe(struct net_device *dev) | |||
| 790 | } | 791 | } |
| 791 | 792 | ||
| 792 | phydev = phy_connect(dev, phydev->dev.bus_id, | 793 | phydev = phy_connect(dev, phydev->dev.bus_id, |
| 793 | &smsc911x_phy_adjust_link, 0, pdata->phy_interface); | 794 | &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); |
| 794 | 795 | ||
| 795 | if (IS_ERR(phydev)) { | 796 | if (IS_ERR(phydev)) { |
| 796 | pr_err("%s: Could not attach to PHY\n", dev->name); | 797 | pr_err("%s: Could not attach to PHY\n", dev->name); |
| @@ -1205,14 +1206,14 @@ static int smsc911x_open(struct net_device *dev) | |||
| 1205 | /* Set interrupt deassertion to 100uS */ | 1206 | /* Set interrupt deassertion to 100uS */ |
| 1206 | intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); | 1207 | intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); |
| 1207 | 1208 | ||
| 1208 | if (pdata->irq_polarity) { | 1209 | if (pdata->config.irq_polarity) { |
| 1209 | SMSC_TRACE(IFUP, "irq polarity: active high"); | 1210 | SMSC_TRACE(IFUP, "irq polarity: active high"); |
| 1210 | intcfg |= INT_CFG_IRQ_POL_; | 1211 | intcfg |= INT_CFG_IRQ_POL_; |
| 1211 | } else { | 1212 | } else { |
| 1212 | SMSC_TRACE(IFUP, "irq polarity: active low"); | 1213 | SMSC_TRACE(IFUP, "irq polarity: active low"); |
| 1213 | } | 1214 | } |
| 1214 | 1215 | ||
| 1215 | if (pdata->irq_type) { | 1216 | if (pdata->config.irq_type) { |
| 1216 | SMSC_TRACE(IFUP, "irq type: push-pull"); | 1217 | SMSC_TRACE(IFUP, "irq type: push-pull"); |
| 1217 | intcfg |= INT_CFG_IRQ_TYPE_; | 1218 | intcfg |= INT_CFG_IRQ_TYPE_; |
| 1218 | } else { | 1219 | } else { |
| @@ -1767,9 +1768,7 @@ static int __devinit smsc911x_init(struct net_device *dev) | |||
| 1767 | SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); | 1768 | SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); |
| 1768 | SMSC_TRACE(PROBE, "PHY will be autodetected."); | 1769 | SMSC_TRACE(PROBE, "PHY will be autodetected."); |
| 1769 | 1770 | ||
| 1770 | #if (!SMSC_CAN_USE_32BIT) | ||
| 1771 | spin_lock_init(&pdata->dev_lock); | 1771 | spin_lock_init(&pdata->dev_lock); |
| 1772 | #endif | ||
| 1773 | 1772 | ||
| 1774 | if (pdata->ioaddr == 0) { | 1773 | if (pdata->ioaddr == 0) { |
| 1775 | SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); | 1774 | SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); |
| @@ -1910,6 +1909,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
| 1910 | { | 1909 | { |
| 1911 | struct net_device *dev; | 1910 | struct net_device *dev; |
| 1912 | struct smsc911x_data *pdata; | 1911 | struct smsc911x_data *pdata; |
| 1912 | struct smsc911x_platform_config *config = pdev->dev.platform_data; | ||
| 1913 | struct resource *res; | 1913 | struct resource *res; |
| 1914 | unsigned int intcfg = 0; | 1914 | unsigned int intcfg = 0; |
| 1915 | int res_size; | 1915 | int res_size; |
| @@ -1918,6 +1918,13 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
| 1918 | 1918 | ||
| 1919 | pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); | 1919 | pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); |
| 1920 | 1920 | ||
| 1921 | /* platform data specifies irq & dynamic bus configuration */ | ||
| 1922 | if (!pdev->dev.platform_data) { | ||
| 1923 | pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); | ||
| 1924 | retval = -ENODEV; | ||
| 1925 | goto out_0; | ||
| 1926 | } | ||
| 1927 | |||
| 1921 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 1928 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 1922 | "smsc911x-memory"); | 1929 | "smsc911x-memory"); |
| 1923 | if (!res) | 1930 | if (!res) |
| @@ -1949,15 +1956,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
| 1949 | dev->irq = platform_get_irq(pdev, 0); | 1956 | dev->irq = platform_get_irq(pdev, 0); |
| 1950 | pdata->ioaddr = ioremap_nocache(res->start, res_size); | 1957 | pdata->ioaddr = ioremap_nocache(res->start, res_size); |
| 1951 | 1958 | ||
| 1952 | /* copy config parameters across if present, otherwise pdata | 1959 | /* copy config parameters across to pdata */ |
| 1953 | * defaults to zeros */ | 1960 | memcpy(&pdata->config, config, sizeof(pdata->config)); |
| 1954 | if (pdev->dev.platform_data) { | ||
| 1955 | struct smsc911x_platform_config *config = | ||
| 1956 | pdev->dev.platform_data; | ||
| 1957 | pdata->irq_polarity = config->irq_polarity; | ||
| 1958 | pdata->irq_type = config->irq_type; | ||
| 1959 | pdata->phy_interface = config->phy_interface; | ||
| 1960 | } | ||
| 1961 | 1961 | ||
| 1962 | pdata->dev = dev; | 1962 | pdata->dev = dev; |
| 1963 | pdata->msg_enable = ((1 << debug) - 1); | 1963 | pdata->msg_enable = ((1 << debug) - 1); |
| @@ -1974,10 +1974,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
| 1974 | goto out_unmap_io_3; | 1974 | goto out_unmap_io_3; |
| 1975 | 1975 | ||
| 1976 | /* configure irq polarity and type before connecting isr */ | 1976 | /* configure irq polarity and type before connecting isr */ |
| 1977 | if (pdata->irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) | 1977 | if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) |
| 1978 | intcfg |= INT_CFG_IRQ_POL_; | 1978 | intcfg |= INT_CFG_IRQ_POL_; |
| 1979 | 1979 | ||
| 1980 | if (pdata->irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL) | 1980 | if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL) |
| 1981 | intcfg |= INT_CFG_IRQ_TYPE_; | 1981 | intcfg |= INT_CFG_IRQ_TYPE_; |
| 1982 | 1982 | ||
| 1983 | smsc911x_reg_write(pdata, INT_CFG, intcfg); | 1983 | smsc911x_reg_write(pdata, INT_CFG, intcfg); |
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h index feb36de274ca..f818cf0415f7 100644 --- a/drivers/net/smsc911x.h +++ b/drivers/net/smsc911x.h | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #ifndef __SMSC911X_H__ | 21 | #ifndef __SMSC911X_H__ |
| 22 | #define __SMSC911X_H__ | 22 | #define __SMSC911X_H__ |
| 23 | 23 | ||
| 24 | #define SMSC_CAN_USE_32BIT 1 | ||
| 25 | #define TX_FIFO_LOW_THRESHOLD ((u32)1600) | 24 | #define TX_FIFO_LOW_THRESHOLD ((u32)1600) |
| 26 | #define SMSC911X_EEPROM_SIZE ((u32)7) | 25 | #define SMSC911X_EEPROM_SIZE ((u32)7) |
| 27 | #define USE_DEBUG 0 | 26 | #define USE_DEBUG 0 |
diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h index 47c4ffd10dbb..1cbf0313adde 100644 --- a/include/linux/smsc911x.h +++ b/include/linux/smsc911x.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | struct smsc911x_platform_config { | 28 | struct smsc911x_platform_config { |
| 29 | unsigned int irq_polarity; | 29 | unsigned int irq_polarity; |
| 30 | unsigned int irq_type; | 30 | unsigned int irq_type; |
| 31 | unsigned int flags; | ||
| 31 | phy_interface_t phy_interface; | 32 | phy_interface_t phy_interface; |
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| @@ -39,4 +40,8 @@ struct smsc911x_platform_config { | |||
| 39 | #define SMSC911X_IRQ_TYPE_OPEN_DRAIN 0 | 40 | #define SMSC911X_IRQ_TYPE_OPEN_DRAIN 0 |
| 40 | #define SMSC911X_IRQ_TYPE_PUSH_PULL 1 | 41 | #define SMSC911X_IRQ_TYPE_PUSH_PULL 1 |
| 41 | 42 | ||
| 43 | /* Constants for flags */ | ||
| 44 | #define SMSC911X_USE_16BIT (BIT(0)) | ||
| 45 | #define SMSC911X_USE_32BIT (BIT(1)) | ||
| 46 | |||
| 42 | #endif /* __LINUX_SMSC911X_H__ */ | 47 | #endif /* __LINUX_SMSC911X_H__ */ |
