aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/smsc/smsc911x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/smsc/smsc911x.c')
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c154
1 files changed, 93 insertions, 61 deletions
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 24d2df068d7..5e13fa5524a 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
***************************************************************************
* Rewritten, heavily based on smsc911x simple driver by SMSC.
@@ -33,6 +32,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/crc32.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -144,6 +144,9 @@ struct smsc911x_data {
/* regulators */
struct regulator_bulk_data supplies[SMSC911X_NUM_SUPPLIES];
+
+ /* clock */
+ struct clk *clk;
};
/* Easy access to information */
@@ -253,7 +256,7 @@ smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
- writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
+ iowrite32_rep(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
goto out;
}
@@ -285,7 +288,7 @@ smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
- writesl(pdata->ioaddr + __smsc_shift(pdata,
+ iowrite32_rep(pdata->ioaddr + __smsc_shift(pdata,
TX_DATA_FIFO), buf, wordcount);
goto out;
}
@@ -319,7 +322,7 @@ smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
- readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
+ ioread32_rep(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
goto out;
}
@@ -351,7 +354,7 @@ smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
- readsl(pdata->ioaddr + __smsc_shift(pdata,
+ ioread32_rep(pdata->ioaddr + __smsc_shift(pdata,
RX_DATA_FIFO), buf, wordcount);
goto out;
}
@@ -369,7 +372,7 @@ out:
}
/*
- * enable resources, currently just regulators.
+ * enable regulator and clock resources.
*/
static int smsc911x_enable_resources(struct platform_device *pdev)
{
@@ -382,6 +385,13 @@ static int smsc911x_enable_resources(struct platform_device *pdev)
if (ret)
netdev_err(ndev, "failed to enable regulators %d\n",
ret);
+
+ if (!IS_ERR(pdata->clk)) {
+ ret = clk_prepare_enable(pdata->clk);
+ if (ret < 0)
+ netdev_err(ndev, "failed to enable clock %d\n", ret);
+ }
+
return ret;
}
@@ -396,6 +406,10 @@ static int smsc911x_disable_resources(struct platform_device *pdev)
ret = regulator_bulk_disable(ARRAY_SIZE(pdata->supplies),
pdata->supplies);
+
+ if (!IS_ERR(pdata->clk))
+ clk_disable_unprepare(pdata->clk);
+
return ret;
}
@@ -421,6 +435,13 @@ static int smsc911x_request_resources(struct platform_device *pdev)
if (ret)
netdev_err(ndev, "couldn't get regulators %d\n",
ret);
+
+ /* Request clock */
+ pdata->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pdata->clk))
+ dev_dbg(&pdev->dev, "couldn't get clock %li\n",
+ PTR_ERR(pdata->clk));
+
return ret;
}
@@ -436,6 +457,12 @@ static void smsc911x_free_resources(struct platform_device *pdev)
/* Free regulators */
regulator_bulk_free(ARRAY_SIZE(pdata->supplies),
pdata->supplies);
+
+ /* Free clock */
+ if (!IS_ERR(pdata->clk)) {
+ clk_put(pdata->clk);
+ pdata->clk = NULL;
+ }
}
/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read
@@ -997,9 +1024,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
phydev->addr, phydev->phy_id);
- ret = phy_connect_direct(dev, phydev,
- &smsc911x_phy_adjust_link, 0,
- pdata->config.phy_interface);
+ ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link,
+ pdata->config.phy_interface);
if (ret) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -1031,8 +1057,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
return 0;
}
-static int __devinit smsc911x_mii_init(struct platform_device *pdev,
- struct net_device *dev)
+static int smsc911x_mii_init(struct platform_device *pdev,
+ struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
int err = -ENXIO, i;
@@ -1166,10 +1192,8 @@ smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat)
/* Quickly dumps bad packets */
static void
-smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
+smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktwords)
{
- unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2;
-
if (likely(pktwords >= 4)) {
unsigned int timeout = 500;
unsigned int val;
@@ -1233,7 +1257,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
continue;
}
- skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);
+ skb = netdev_alloc_skb(dev, pktwords << 2);
if (unlikely(!skb)) {
SMSC_WARN(pdata, rx_err,
"Unable to allocate skb for rx packet");
@@ -1243,14 +1267,12 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
break;
}
- skb->data = skb->head;
- skb_reset_tail_pointer(skb);
+ pdata->ops->rx_readfifo(pdata,
+ (unsigned int *)skb->data, pktwords);
/* Align IP on 16B boundary */
skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, pktlength - 4);
- pdata->ops->rx_readfifo(pdata,
- (unsigned int *)skb->head, pktwords);
skb->protocol = eth_type_trans(skb, dev);
skb_checksum_none_assert(skb);
netif_receive_skb(skb);
@@ -1446,6 +1468,14 @@ smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
smsc911x_mac_write(pdata, ADDRL, mac_low32);
}
+static void smsc911x_disable_irq_chip(struct net_device *dev)
+{
+ struct smsc911x_data *pdata = netdev_priv(dev);
+
+ smsc911x_reg_write(pdata, INT_EN, 0);
+ smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+}
+
static int smsc911x_open(struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
@@ -1459,11 +1489,6 @@ static int smsc911x_open(struct net_device *dev)
return -EAGAIN;
}
- if (!is_valid_ether_addr(dev->dev_addr)) {
- SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address");
- return -EADDRNOTAVAIL;
- }
-
/* Reset the LAN911x */
if (smsc911x_soft_reset(pdata)) {
SMSC_WARN(pdata, hw, "soft reset failed");
@@ -1498,8 +1523,7 @@ static int smsc911x_open(struct net_device *dev)
spin_unlock_irq(&pdata->mac_lock);
/* Initialise irqs, but leave all sources disabled */
- smsc911x_reg_write(pdata, INT_EN, 0);
- smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+ smsc911x_disable_irq_chip(dev);
/* Set interrupt deassertion to 100uS */
intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
@@ -1565,7 +1589,7 @@ static int smsc911x_open(struct net_device *dev)
smsc911x_reg_write(pdata, FIFO_INT, temp);
/* set RX Data offset to 2 bytes for alignment */
- smsc911x_reg_write(pdata, RX_CFG, (2 << 8));
+ smsc911x_reg_write(pdata, RX_CFG, (NET_IP_ALIGN << 8));
/* enable NAPI polling before enabling RX interrupts */
napi_enable(&pdata->napi);
@@ -1649,7 +1673,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
freespace -= (skb->len + 32);
skb_tx_timestamp(skb);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
smsc911x_tx_update_txcounters(dev);
@@ -2069,6 +2093,7 @@ static const struct ethtool_ops smsc911x_ethtool_ops = {
.get_eeprom_len = smsc911x_ethtool_get_eeprom_len,
.get_eeprom = smsc911x_ethtool_get_eeprom,
.set_eeprom = smsc911x_ethtool_set_eeprom,
+ .get_ts_info = ethtool_op_get_ts_info,
};
static const struct net_device_ops smsc911x_netdev_ops = {
@@ -2087,7 +2112,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
};
/* copies the current mac address from hardware to dev->dev_addr */
-static void __devinit smsc911x_read_mac_address(struct net_device *dev)
+static void smsc911x_read_mac_address(struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH);
@@ -2102,10 +2127,10 @@ static void __devinit smsc911x_read_mac_address(struct net_device *dev)
}
/* Initializing private device structures, only called from probe */
-static int __devinit smsc911x_init(struct net_device *dev)
+static int smsc911x_init(struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int byte_test;
+ unsigned int byte_test, mask;
unsigned int to = 100;
SMSC_TRACE(pdata, probe, "Driver Parameters:");
@@ -2117,7 +2142,7 @@ static int __devinit smsc911x_init(struct net_device *dev)
spin_lock_init(&pdata->dev_lock);
spin_lock_init(&pdata->mac_lock);
- if (pdata->ioaddr == 0) {
+ if (pdata->ioaddr == NULL) {
SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000");
return -ENODEV;
}
@@ -2125,11 +2150,24 @@ static int __devinit smsc911x_init(struct net_device *dev)
/*
* poll the READY bit in PMT_CTRL. Any other access to the device is
* forbidden while this bit isn't set. Try for 100ms
+ *
+ * Note that this test is done before the WORD_SWAP register is
+ * programmed. So in some configurations the READY bit is at 16 before
+ * WORD_SWAP is written to. This issue is worked around by waiting
+ * until either bit 0 or bit 16 gets set in PMT_CTRL.
+ *
+ * SMSC has confirmed that checking bit 16 (marked as reserved in
+ * the datasheet) is fine since these bits "will either never be set
+ * or can only go high after READY does (so also indicate the device
+ * is ready)".
*/
- while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
+
+ mask = PMT_CTRL_READY_ | swahw32(PMT_CTRL_READY_);
+ while (!(smsc911x_reg_read(pdata, PMT_CTRL) & mask) && --to)
udelay(1000);
+
if (to == 0) {
- pr_err("Device not READY in 100ms aborting\n");
+ netdev_err(dev, "Device not READY in 100ms aborting\n");
return -ENODEV;
}
@@ -2217,9 +2255,6 @@ static int __devinit smsc911x_init(struct net_device *dev)
if (smsc911x_soft_reset(pdata))
return -ENODEV;
- /* Disable all interrupt sources until we bring the device up */
- smsc911x_reg_write(pdata, INT_EN, 0);
-
ether_setup(dev);
dev->flags |= IFF_MULTICAST;
netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT);
@@ -2229,7 +2264,7 @@ static int __devinit smsc911x_init(struct net_device *dev)
return 0;
}
-static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
+static int smsc911x_drv_remove(struct platform_device *pdev)
{
struct net_device *dev;
struct smsc911x_data *pdata;
@@ -2249,7 +2284,6 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
mdiobus_unregister(pdata->mii_bus);
mdiobus_free(pdata->mii_bus);
- platform_set_drvdata(pdev, NULL);
unregister_netdev(dev);
free_irq(dev->irq, dev);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -2286,9 +2320,8 @@ static const struct smsc911x_ops shifted_smsc911x_ops = {
};
#ifdef CONFIG_OF
-static int __devinit smsc911x_probe_config_dt(
- struct smsc911x_platform_config *config,
- struct device_node *np)
+static int smsc911x_probe_config_dt(struct smsc911x_platform_config *config,
+ struct device_node *np)
{
const char *mac;
u32 width = 0;
@@ -2336,19 +2369,17 @@ static inline int smsc911x_probe_config_dt(
}
#endif /* CONFIG_OF */
-static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+static int smsc911x_drv_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct net_device *dev;
struct smsc911x_data *pdata;
- struct smsc911x_platform_config *config = pdev->dev.platform_data;
+ struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev);
struct resource *res, *irq_res;
unsigned int intcfg = 0;
int res_size, irq_flags;
int retval;
- pr_info("Driver version %s\n", SMSC_DRV_VERSION);
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"smsc911x-memory");
if (!res)
@@ -2374,7 +2405,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
dev = alloc_etherdev(sizeof(struct smsc911x_data));
if (!dev) {
- pr_warn("Could not allocate device\n");
retval = -ENOMEM;
goto out_release_io_1;
}
@@ -2382,7 +2412,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
SET_NETDEV_DEV(dev, &pdev->dev);
pdata = netdev_priv(dev);
-
dev->irq = irq_res->start;
irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
pdata->ioaddr = ioremap_nocache(res->start, res_size);
@@ -2394,11 +2423,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
retval = smsc911x_request_resources(pdev);
if (retval)
- goto out_return_resources;
+ goto out_request_resources_fail;
retval = smsc911x_enable_resources(pdev);
if (retval)
- goto out_disable_resources;
+ goto out_enable_resources_fail;
if (pdata->ioaddr == NULL) {
SMSC_WARN(pdata, probe, "Error smsc911x base address invalid");
@@ -2438,17 +2467,18 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
smsc911x_reg_write(pdata, INT_CFG, intcfg);
/* Ensure interrupts are globally disabled before connecting ISR */
- smsc911x_reg_write(pdata, INT_EN, 0);
- smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+ smsc911x_disable_irq_chip(dev);
retval = request_irq(dev->irq, smsc911x_irqhandler,
irq_flags | IRQF_SHARED, dev->name, dev);
if (retval) {
SMSC_WARN(pdata, probe,
"Unable to claim requested irq: %d", dev->irq);
- goto out_free_irq;
+ goto out_disable_resources;
}
+ netif_carrier_off(dev);
+
retval = register_netdev(dev);
if (retval) {
SMSC_WARN(pdata, probe, "Error %i registering device", retval);
@@ -2472,7 +2502,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
SMSC_TRACE(pdata, probe,
"MAC Address is specified by configuration");
} else if (is_valid_ether_addr(pdata->config.mac)) {
- memcpy(dev->dev_addr, pdata->config.mac, 6);
+ memcpy(dev->dev_addr, pdata->config.mac, ETH_ALEN);
SMSC_TRACE(pdata, probe,
"MAC Address specified by platform data");
} else {
@@ -2486,10 +2516,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
"Mac Address is read from LAN911x EEPROM");
} else {
/* eeprom values are invalid, generate random MAC */
- random_ether_addr(dev->dev_addr);
+ eth_hw_addr_random(dev);
smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
SMSC_TRACE(pdata, probe,
- "MAC Address is set to random_ether_addr");
+ "MAC Address is set to eth_random_addr");
}
}
@@ -2505,9 +2535,9 @@ out_free_irq:
free_irq(dev->irq, dev);
out_disable_resources:
(void)smsc911x_disable_resources(pdev);
-out_return_resources:
+out_enable_resources_fail:
smsc911x_free_resources(pdev);
- platform_set_drvdata(pdev, NULL);
+out_request_resources_fail:
iounmap(pdata->ioaddr);
free_netdev(dev);
out_release_io_1:
@@ -2568,20 +2598,22 @@ static const struct dev_pm_ops smsc911x_pm_ops = {
#define SMSC911X_PM_OPS NULL
#endif
+#ifdef CONFIG_OF
static const struct of_device_id smsc911x_dt_ids[] = {
{ .compatible = "smsc,lan9115", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
+#endif
static struct platform_driver smsc911x_driver = {
.probe = smsc911x_drv_probe,
- .remove = __devexit_p(smsc911x_drv_remove),
+ .remove = smsc911x_drv_remove,
.driver = {
.name = SMSC_CHIPNAME,
.owner = THIS_MODULE,
.pm = SMSC911X_PM_OPS,
- .of_match_table = smsc911x_dt_ids,
+ .of_match_table = of_match_ptr(smsc911x_dt_ids),
},
};