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 /drivers/net | |
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/smsc911x.c | 158 | ||||
-rw-r--r-- | drivers/net/smsc911x.h | 1 |
2 files changed, 79 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 |