Commit 6dffbe53 authored by Tony Prisk's avatar Tony Prisk Committed by David S. Miller

net: velocity: Add platform device support to VIA velocity driver

Add support for the VIA Velocity network driver to be bound to a
OF created platform device.
Signed-off-by: default avatarTony Prisk <linux@prisktech.co.nz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e2c41f14
* VIA Velocity 10/100/1000 Network Controller
Required properties:
- compatible : Should be "via,velocity-vt6110"
- reg : Address and length of the io space
- interrupts : Should contain the controller interrupt line
Optional properties:
- no-eeprom : PCI network cards use an external EEPROM to store data. Embedded
devices quite often set this data in uboot and do not provide an eeprom.
Specify this option if you have no external eeprom.
Examples:
eth0@d8004000 {
compatible = "via,velocity-vt6110";
reg = <0xd8004000 0x400>;
interrupts = <10>;
no-eeprom;
};
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
config NET_VENDOR_VIA config NET_VENDOR_VIA
bool "VIA devices" bool "VIA devices"
default y default y
depends on PCI
---help--- ---help---
If you have a network (Ethernet) card belonging to this class, say Y If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from and read the Ethernet-HOWTO, available from
...@@ -45,7 +44,7 @@ config VIA_RHINE_MMIO ...@@ -45,7 +44,7 @@ config VIA_RHINE_MMIO
config VIA_VELOCITY config VIA_VELOCITY
tristate "VIA Velocity support" tristate "VIA Velocity support"
depends on PCI depends on (PCI || USE_OF)
select CRC32 select CRC32
select CRC_CCITT select CRC_CCITT
select NET_CORE select NET_CORE
......
...@@ -65,7 +65,11 @@ ...@@ -65,7 +65,11 @@
#include <linux/if.h> #include <linux/if.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/platform_device.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
...@@ -80,10 +84,24 @@ ...@@ -80,10 +84,24 @@
#include "via-velocity.h" #include "via-velocity.h"
enum velocity_bus_type {
BUS_PCI,
BUS_PLATFORM,
};
static int velocity_nics; static int velocity_nics;
static int msglevel = MSG_LEVEL_INFO; static int msglevel = MSG_LEVEL_INFO;
static void velocity_set_power_state(struct velocity_info *vptr, char state)
{
void *addr = vptr->mac_regs;
if (vptr->pdev)
pci_set_power_state(vptr->pdev, state);
else
writeb(state, addr + 0x154);
}
/** /**
* mac_get_cam_mask - Read a CAM mask * mac_get_cam_mask - Read a CAM mask
* @regs: register block for this velocity * @regs: register block for this velocity
...@@ -362,12 +380,23 @@ static struct velocity_info_tbl chip_info_table[] = { ...@@ -362,12 +380,23 @@ static struct velocity_info_tbl chip_info_table[] = {
* Describe the PCI device identifiers that we support in this * Describe the PCI device identifiers that we support in this
* device driver. Used for hotplug autoloading. * device driver. Used for hotplug autoloading.
*/ */
static DEFINE_PCI_DEVICE_TABLE(velocity_id_table) = {
static DEFINE_PCI_DEVICE_TABLE(velocity_pci_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ } { }
}; };
MODULE_DEVICE_TABLE(pci, velocity_id_table); MODULE_DEVICE_TABLE(pci, velocity_pci_id_table);
/**
* Describe the OF device identifiers that we support in this
* device driver. Used for devicetree nodes.
*/
static struct of_device_id velocity_of_ids[] = {
{ .compatible = "via,velocity-vt6110", .data = &chip_info_table[0] },
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, velocity_of_ids);
/** /**
* get_chip_name - identifier to name * get_chip_name - identifier to name
...@@ -385,29 +414,6 @@ static const char *get_chip_name(enum chip_type chip_id) ...@@ -385,29 +414,6 @@ static const char *get_chip_name(enum chip_type chip_id)
return chip_info_table[i].name; return chip_info_table[i].name;
} }
/**
* velocity_remove1 - device unplug
* @pdev: PCI device being removed
*
* Device unload callback. Called on an unplug or on module
* unload for each active device that is present. Disconnects
* the device from the network layer and frees all the resources
*/
static void velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct velocity_info *vptr = netdev_priv(dev);
unregister_netdev(dev);
iounmap(vptr->mac_regs);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
velocity_nics--;
}
/** /**
* velocity_set_int_opt - parser for integer options * velocity_set_int_opt - parser for integer options
* @opt: pointer to option value * @opt: pointer to option value
...@@ -1181,6 +1187,17 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) ...@@ -1181,6 +1187,17 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
u16 BMCR; u16 BMCR;
switch (PHYID_GET_PHY_ID(vptr->phy_id)) { switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
case PHYID_ICPLUS_IP101A:
MII_REG_BITS_ON((ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP),
MII_ADVERTISE, vptr->mac_regs);
if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
MII_REG_BITS_ON(TCSR_ECHODIS, MII_SREVISION,
vptr->mac_regs);
else
MII_REG_BITS_OFF(TCSR_ECHODIS, MII_SREVISION,
vptr->mac_regs);
MII_REG_BITS_ON(PLED_LALBE, MII_TPISTATUS, vptr->mac_regs);
break;
case PHYID_CICADA_CS8201: case PHYID_CICADA_CS8201:
/* /*
* Reset to hardware default * Reset to hardware default
...@@ -1312,6 +1329,7 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1312,6 +1329,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type) enum velocity_init_type type)
{ {
struct mac_regs __iomem *regs = vptr->mac_regs; struct mac_regs __iomem *regs = vptr->mac_regs;
struct net_device *netdev = vptr->netdev;
int i, mii_status; int i, mii_status;
mac_wol_reset(regs); mac_wol_reset(regs);
...@@ -1320,7 +1338,7 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1320,7 +1338,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
case VELOCITY_INIT_RESET: case VELOCITY_INIT_RESET:
case VELOCITY_INIT_WOL: case VELOCITY_INIT_WOL:
netif_stop_queue(vptr->netdev); netif_stop_queue(netdev);
/* /*
* Reset RX to prevent RX pointer not on the 4X location * Reset RX to prevent RX pointer not on the 4X location
...@@ -1333,7 +1351,7 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1333,7 +1351,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
velocity_print_link_status(vptr); velocity_print_link_status(vptr);
if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
netif_wake_queue(vptr->netdev); netif_wake_queue(netdev);
} }
enable_flow_control_ability(vptr); enable_flow_control_ability(vptr);
...@@ -1353,9 +1371,11 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1353,9 +1371,11 @@ static void velocity_init_registers(struct velocity_info *vptr,
velocity_soft_reset(vptr); velocity_soft_reset(vptr);
mdelay(5); mdelay(5);
mac_eeprom_reload(regs); if (!vptr->no_eeprom) {
for (i = 0; i < 6; i++) mac_eeprom_reload(regs);
writeb(vptr->netdev->dev_addr[i], &(regs->PAR[i])); for (i = 0; i < 6; i++)
writeb(netdev->dev_addr[i], regs->PAR + i);
}
/* /*
* clear Pre_ACPI bit. * clear Pre_ACPI bit.
...@@ -1378,7 +1398,7 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1378,7 +1398,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
/* /*
* Set packet filter: Receive directed and broadcast address * Set packet filter: Receive directed and broadcast address
*/ */
velocity_set_multi(vptr->netdev); velocity_set_multi(netdev);
/* /*
* Enable MII auto-polling * Enable MII auto-polling
...@@ -1405,14 +1425,14 @@ static void velocity_init_registers(struct velocity_info *vptr, ...@@ -1405,14 +1425,14 @@ static void velocity_init_registers(struct velocity_info *vptr,
writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set); writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
mii_status = velocity_get_opt_media_mode(vptr); mii_status = velocity_get_opt_media_mode(vptr);
netif_stop_queue(vptr->netdev); netif_stop_queue(netdev);
mii_init(vptr, mii_status); mii_init(vptr, mii_status);
if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
velocity_print_link_status(vptr); velocity_print_link_status(vptr);
if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
netif_wake_queue(vptr->netdev); netif_wake_queue(netdev);
} }
enable_flow_control_ability(vptr); enable_flow_control_ability(vptr);
...@@ -2233,15 +2253,15 @@ static int velocity_open(struct net_device *dev) ...@@ -2233,15 +2253,15 @@ static int velocity_open(struct net_device *dev)
goto out; goto out;
/* Ensure chip is running */ /* Ensure chip is running */
pci_set_power_state(vptr->pdev, PCI_D0); velocity_set_power_state(vptr, PCI_D0);
velocity_init_registers(vptr, VELOCITY_INIT_COLD); velocity_init_registers(vptr, VELOCITY_INIT_COLD);
ret = request_irq(vptr->pdev->irq, velocity_intr, IRQF_SHARED, ret = request_irq(dev->irq, velocity_intr, IRQF_SHARED,
dev->name, dev); dev->name, dev);
if (ret < 0) { if (ret < 0) {
/* Power down the chip */ /* Power down the chip */
pci_set_power_state(vptr->pdev, PCI_D3hot); velocity_set_power_state(vptr, PCI_D3hot);
velocity_free_rings(vptr); velocity_free_rings(vptr);
goto out; goto out;
} }
...@@ -2314,6 +2334,7 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu) ...@@ -2314,6 +2334,7 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
tmp_vptr->netdev = dev; tmp_vptr->netdev = dev;
tmp_vptr->pdev = vptr->pdev; tmp_vptr->pdev = vptr->pdev;
tmp_vptr->dev = vptr->dev;
tmp_vptr->options = vptr->options; tmp_vptr->options = vptr->options;
tmp_vptr->tx.numq = vptr->tx.numq; tmp_vptr->tx.numq = vptr->tx.numq;
...@@ -2413,7 +2434,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -2413,7 +2434,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
saving then we need to bring the device back up to talk to it */ saving then we need to bring the device back up to talk to it */
if (!netif_running(dev)) if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0); velocity_set_power_state(vptr, PCI_D0);
switch (cmd) { switch (cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
...@@ -2426,7 +2447,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -2426,7 +2447,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
if (!netif_running(dev)) if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot); velocity_set_power_state(vptr, PCI_D3hot);
return ret; return ret;
...@@ -2492,7 +2513,7 @@ static int velocity_close(struct net_device *dev) ...@@ -2492,7 +2513,7 @@ static int velocity_close(struct net_device *dev)
if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
velocity_get_ip(vptr); velocity_get_ip(vptr);
free_irq(vptr->pdev->irq, dev); free_irq(dev->irq, dev);
velocity_free_rings(vptr); velocity_free_rings(vptr);
...@@ -2631,13 +2652,9 @@ static const struct net_device_ops velocity_netdev_ops = { ...@@ -2631,13 +2652,9 @@ static const struct net_device_ops velocity_netdev_ops = {
* Set up the initial velocity_info struct for the device that has been * Set up the initial velocity_info struct for the device that has been
* discovered. * discovered.
*/ */
static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, static void velocity_init_info(struct velocity_info *vptr,
const struct velocity_info_tbl *info) const struct velocity_info_tbl *info)
{ {
memset(vptr, 0, sizeof(struct velocity_info));
vptr->dev = &pdev->dev;
vptr->pdev = pdev;
vptr->chip_id = info->chip_id; vptr->chip_id = info->chip_id;
vptr->tx.numq = info->txqueue; vptr->tx.numq = info->txqueue;
vptr->multicast_limit = MCAM_SIZE; vptr->multicast_limit = MCAM_SIZE;
...@@ -2652,10 +2669,9 @@ static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, ...@@ -2652,10 +2669,9 @@ static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
* Retrieve the PCI configuration space data that interests us from * Retrieve the PCI configuration space data that interests us from
* the kernel PCI layer * the kernel PCI layer
*/ */
static int velocity_get_pci_info(struct velocity_info *vptr, static int velocity_get_pci_info(struct velocity_info *vptr)
struct pci_dev *pdev)
{ {
vptr->rev_id = pdev->revision; struct pci_dev *pdev = vptr->pdev;
pci_set_master(pdev); pci_set_master(pdev);
...@@ -2678,7 +2694,37 @@ static int velocity_get_pci_info(struct velocity_info *vptr, ...@@ -2678,7 +2694,37 @@ static int velocity_get_pci_info(struct velocity_info *vptr,
dev_err(&pdev->dev, "region #1 is too small.\n"); dev_err(&pdev->dev, "region #1 is too small.\n");
return -EINVAL; return -EINVAL;
} }
vptr->pdev = pdev;
return 0;
}
/**
* velocity_get_platform_info - retrieve platform info for device
* @vptr: velocity device
* @pdev: platform device it matches
*
* Retrieve the Platform configuration data that interests us
*/
static int velocity_get_platform_info(struct velocity_info *vptr)
{
struct resource res;
int ret;
if (of_get_property(vptr->dev->of_node, "no-eeprom", NULL))
vptr->no_eeprom = 1;
ret = of_address_to_resource(vptr->dev->of_node, 0, &res);
if (ret) {
dev_err(vptr->dev, "unable to find memory address\n");
return ret;
}
vptr->memaddr = res.start;
if (resource_size(&res) < VELOCITY_IO_SIZE) {
dev_err(vptr->dev, "memory region is too small.\n");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -2707,21 +2753,22 @@ static u32 velocity_get_link(struct net_device *dev) ...@@ -2707,21 +2753,22 @@ static u32 velocity_get_link(struct net_device *dev)
} }
/** /**
* velocity_found1 - set up discovered velocity card * velocity_probe - set up discovered velocity device
* @pdev: PCI device * @pdev: PCI device
* @ent: PCI device table entry that matched * @ent: PCI device table entry that matched
* @bustype: bus that device is connected to
* *
* Configure a discovered adapter from scratch. Return a negative * Configure a discovered adapter from scratch. Return a negative
* errno error code on failure paths. * errno error code on failure paths.
*/ */
static int velocity_found1(struct pci_dev *pdev, static int velocity_probe(struct device *dev, int irq,
const struct pci_device_id *ent) const struct velocity_info_tbl *info,
enum velocity_bus_type bustype)
{ {
static int first = 1; static int first = 1;
struct net_device *dev; struct net_device *netdev;
int i; int i;
const char *drv_string; const char *drv_string;
const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
struct velocity_info *vptr; struct velocity_info *vptr;
struct mac_regs __iomem *regs; struct mac_regs __iomem *regs;
int ret = -ENOMEM; int ret = -ENOMEM;
...@@ -2730,19 +2777,18 @@ static int velocity_found1(struct pci_dev *pdev, ...@@ -2730,19 +2777,18 @@ static int velocity_found1(struct pci_dev *pdev,
* can support more than MAX_UNITS. * can support more than MAX_UNITS.
*/ */
if (velocity_nics >= MAX_UNITS) { if (velocity_nics >= MAX_UNITS) {
dev_notice(&pdev->dev, "already found %d NICs.\n", dev_notice(dev, "already found %d NICs.\n", velocity_nics);
velocity_nics);
return -ENODEV; return -ENODEV;
} }
dev = alloc_etherdev(sizeof(struct velocity_info)); netdev = alloc_etherdev(sizeof(struct velocity_info));
if (!dev) if (!netdev)
goto out; goto out;
/* Chain it all together */ /* Chain it all together */
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(netdev, dev);
vptr = netdev_priv(dev); vptr = netdev_priv(netdev);
if (first) { if (first) {
printk(KERN_INFO "%s Ver. %s\n", printk(KERN_INFO "%s Ver. %s\n",
...@@ -2752,41 +2798,41 @@ static int velocity_found1(struct pci_dev *pdev, ...@@ -2752,41 +2798,41 @@ static int velocity_found1(struct pci_dev *pdev,
first = 0; first = 0;
} }
velocity_init_info(pdev, vptr, info); netdev->irq = irq;
vptr->netdev = netdev;
vptr->dev = dev;
vptr->netdev = dev; velocity_init_info(vptr, info);
ret = pci_enable_device(pdev); if (bustype == BUS_PCI) {
if (ret < 0) vptr->pdev = to_pci_dev(dev);
goto err_free_dev;
ret = velocity_get_pci_info(vptr, pdev); ret = velocity_get_pci_info(vptr);
if (ret < 0) { if (ret < 0)
/* error message already printed */ goto err_free_dev;
goto err_disable; } else {
} vptr->pdev = NULL;
ret = velocity_get_platform_info(vptr);
ret = pci_request_regions(pdev, VELOCITY_NAME); if (ret < 0)
if (ret < 0) { goto err_free_dev;
dev_err(&pdev->dev, "No PCI resources.\n");
goto err_disable;
} }
regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
if (regs == NULL) { if (regs == NULL) {
ret = -EIO; ret = -EIO;
goto err_release_res; goto err_free_dev;
} }
vptr->mac_regs = regs; vptr->mac_regs = regs;
vptr->rev_id = readb(&regs->rev_id);
mac_wol_reset(regs); mac_wol_reset(regs);
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(&regs->PAR[i]); netdev->dev_addr[i] = readb(&regs->PAR[i]);
drv_string = dev_driver_string(&pdev->dev); drv_string = dev_driver_string(dev);
velocity_get_options(&vptr->options, velocity_nics, drv_string); velocity_get_options(&vptr->options, velocity_nics, drv_string);
...@@ -2807,46 +2853,125 @@ static int velocity_found1(struct pci_dev *pdev, ...@@ -2807,46 +2853,125 @@ static int velocity_found1(struct pci_dev *pdev,
vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
dev->netdev_ops = &velocity_netdev_ops; netdev->netdev_ops = &velocity_netdev_ops;
dev->ethtool_ops = &velocity_ethtool_ops; netdev->ethtool_ops = &velocity_ethtool_ops;
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); netif_napi_add(netdev, &vptr->napi, velocity_poll,
VELOCITY_NAPI_WEIGHT);
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_HW_VLAN_CTAG_TX; NETIF_F_HW_VLAN_CTAG_TX;
dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER | netdev->features |= NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_IP_CSUM; NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_IP_CSUM;
ret = register_netdev(dev); ret = register_netdev(netdev);
if (ret < 0) if (ret < 0)
goto err_iounmap; goto err_iounmap;
if (!velocity_get_link(dev)) { if (!velocity_get_link(netdev)) {
netif_carrier_off(dev); netif_carrier_off(netdev);
vptr->mii_status |= VELOCITY_LINK_FAIL; vptr->mii_status |= VELOCITY_LINK_FAIL;
} }
velocity_print_info(vptr); velocity_print_info(vptr);
pci_set_drvdata(pdev, dev); dev_set_drvdata(vptr->dev, netdev);
/* and leave the chip powered down */ /* and leave the chip powered down */
pci_set_power_state(pdev, PCI_D3hot); velocity_set_power_state(vptr, PCI_D3hot);
velocity_nics++; velocity_nics++;
out: out:
return ret; return ret;
err_iounmap: err_iounmap:
iounmap(regs); iounmap(regs);
err_release_res:
pci_release_regions(pdev);
err_disable:
pci_disable_device(pdev);
err_free_dev: err_free_dev:
free_netdev(dev); free_netdev(netdev);
goto out; goto out;
} }
#ifdef CONFIG_PM /**
* velocity_remove - device unplug
* @dev: device being removed
*
* Device unload callback. Called on an unplug or on module
* unload for each active device that is present. Disconnects
* the device from the network layer and frees all the resources
*/
static int velocity_remove(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
struct velocity_info *vptr = netdev_priv(netdev);
unregister_netdev(netdev);
iounmap(vptr->mac_regs);
free_netdev(netdev);
velocity_nics--;
return 0;
}
static int velocity_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
const struct velocity_info_tbl *info =
&chip_info_table[ent->driver_data];
int ret;
ret = pci_enable_device(pdev);
if (ret < 0)
return ret;
ret = pci_request_regions(pdev, VELOCITY_NAME);
if (ret < 0) {
dev_err(&pdev->dev, "No PCI resources.\n");
goto fail1;
}
ret = velocity_probe(&pdev->dev, pdev->irq, info, BUS_PCI);
if (ret == 0)
return 0;
pci_release_regions(pdev);
fail1:
pci_disable_device(pdev);
return ret;
}
static void velocity_pci_remove(struct pci_dev *pdev)
{
velocity_remove(&pdev->dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static int velocity_platform_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
const struct velocity_info_tbl *info;
int irq;
of_id = of_match_device(velocity_of_ids, &pdev->dev);
if (!of_id)
return -EINVAL;
info = of_id->data;
irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (!irq)
return -EINVAL;
return velocity_probe(&pdev->dev, irq, info, BUS_PLATFORM);
}
static int velocity_platform_remove(struct platform_device *pdev)
{
velocity_remove(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
/** /**
* wol_calc_crc - WOL CRC * wol_calc_crc - WOL CRC
* @pattern: data pattern * @pattern: data pattern
...@@ -3003,10 +3128,10 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co ...@@ -3003,10 +3128,10 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co
} }
static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) static int velocity_suspend(struct device *dev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *netdev = dev_get_drvdata(dev);
struct velocity_info *vptr = netdev_priv(dev); struct velocity_info *vptr = netdev_priv(netdev);
unsigned long flags; unsigned long flags;
if (!netif_running(vptr->netdev)) if (!netif_running(vptr->netdev))
...@@ -3015,20 +3140,23 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -3015,20 +3140,23 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_detach(vptr->netdev); netif_device_detach(vptr->netdev);
spin_lock_irqsave(&vptr->lock, flags); spin_lock_irqsave(&vptr->lock, flags);
pci_save_state(pdev); if (vptr->pdev)
pci_save_state(vptr->pdev);
if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
velocity_get_ip(vptr); velocity_get_ip(vptr);
velocity_save_context(vptr, &vptr->context); velocity_save_context(vptr, &vptr->context);
velocity_shutdown(vptr); velocity_shutdown(vptr);
velocity_set_wol(vptr); velocity_set_wol(vptr);
pci_enable_wake(pdev, PCI_D3hot, 1); if (vptr->pdev)
pci_set_power_state(pdev, PCI_D3hot); pci_enable_wake(vptr->pdev, PCI_D3hot, 1);
velocity_set_power_state(vptr, PCI_D3hot);
} else { } else {
velocity_save_context(vptr, &vptr->context); velocity_save_context(vptr, &vptr->context);
velocity_shutdown(vptr); velocity_shutdown(vptr);
pci_disable_device(pdev); if (vptr->pdev)
pci_set_power_state(pdev, pci_choose_state(pdev, state)); pci_disable_device(vptr->pdev);
velocity_set_power_state(vptr, PCI_D3hot);
} }
spin_unlock_irqrestore(&vptr->lock, flags); spin_unlock_irqrestore(&vptr->lock, flags);
...@@ -3070,19 +3198,22 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity ...@@ -3070,19 +3198,22 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity
writeb(*((u8 *) (context->mac_reg + i)), ptr + i); writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
} }
static int velocity_resume(struct pci_dev *pdev) static int velocity_resume(struct device *dev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *netdev = dev_get_drvdata(dev);
struct velocity_info *vptr = netdev_priv(dev); struct velocity_info *vptr = netdev_priv(netdev);
unsigned long flags; unsigned long flags;
int i; int i;
if (!netif_running(vptr->netdev)) if (!netif_running(vptr->netdev))
return 0; return 0;
pci_set_power_state(pdev, PCI_D0); velocity_set_power_state(vptr, PCI_D0);
pci_enable_wake(pdev, 0, 0);
pci_restore_state(pdev); if (vptr->pdev) {
pci_enable_wake(vptr->pdev, 0, 0);
pci_restore_state(vptr->pdev);
}
mac_wol_reset(vptr->mac_regs); mac_wol_reset(vptr->mac_regs);
...@@ -3104,23 +3235,34 @@ static int velocity_resume(struct pci_dev *pdev) ...@@ -3104,23 +3235,34 @@ static int velocity_resume(struct pci_dev *pdev)
return 0; return 0;
} }
#endif #endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(velocity_pm_ops, velocity_suspend, velocity_resume);
/* /*
* Definition for our device driver. The PCI layer interface * Definition for our device driver. The PCI layer interface
* uses this to handle all our card discover and plugging * uses this to handle all our card discover and plugging
*/ */
static struct pci_driver velocity_driver = { static struct pci_driver velocity_pci_driver = {
.name = VELOCITY_NAME, .name = VELOCITY_NAME,
.id_table = velocity_id_table, .id_table = velocity_pci_id_table,
.probe = velocity_found1, .probe = velocity_pci_probe,
.remove = velocity_remove1, .remove = velocity_pci_remove,
#ifdef CONFIG_PM .driver = {
.suspend = velocity_suspend, .pm = &velocity_pm_ops,
.resume = velocity_resume, },
#endif
}; };
static struct platform_driver velocity_platform_driver = {
.probe = velocity_platform_probe,
.remove = velocity_platform_remove,
.driver = {
.name = "via-velocity",
.owner = THIS_MODULE,
.of_match_table = velocity_of_ids,
.pm = &velocity_pm_ops,
},
};
/** /**
* velocity_ethtool_up - pre hook for ethtool * velocity_ethtool_up - pre hook for ethtool
...@@ -3133,7 +3275,7 @@ static int velocity_ethtool_up(struct net_device *dev) ...@@ -3133,7 +3275,7 @@ static int velocity_ethtool_up(struct net_device *dev)
{ {
struct velocity_info *vptr = netdev_priv(dev); struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev)) if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0); velocity_set_power_state(vptr, PCI_D0);
return 0; return 0;
} }
...@@ -3148,7 +3290,7 @@ static void velocity_ethtool_down(struct net_device *dev) ...@@ -3148,7 +3290,7 @@ static void velocity_ethtool_down(struct net_device *dev)
{ {
struct velocity_info *vptr = netdev_priv(dev); struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev)) if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot); velocity_set_power_state(vptr, PCI_D3hot);
} }
static int velocity_get_settings(struct net_device *dev, static int velocity_get_settings(struct net_device *dev,
...@@ -3268,9 +3410,14 @@ static int velocity_set_settings(struct net_device *dev, ...@@ -3268,9 +3410,14 @@ static int velocity_set_settings(struct net_device *dev,
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{ {
struct velocity_info *vptr = netdev_priv(dev); struct velocity_info *vptr = netdev_priv(dev);
strlcpy(info->driver, VELOCITY_NAME, sizeof(info->driver)); strlcpy(info->driver, VELOCITY_NAME, sizeof(info->driver));
strlcpy(info->version, VELOCITY_VERSION, sizeof(info->version)); strlcpy(info->version, VELOCITY_VERSION, sizeof(info->version));
strlcpy(info->bus_info, pci_name(vptr->pdev), sizeof(info->bus_info)); if (vptr->pdev)
strlcpy(info->bus_info, pci_name(vptr->pdev),
sizeof(info->bus_info));
else
strlcpy(info->bus_info, "platform", sizeof(info->bus_info));
} }
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
...@@ -3560,13 +3707,20 @@ static void velocity_unregister_notifier(void) ...@@ -3560,13 +3707,20 @@ static void velocity_unregister_notifier(void)
*/ */
static int __init velocity_init_module(void) static int __init velocity_init_module(void)
{ {
int ret; int ret_pci, ret_platform;
velocity_register_notifier(); velocity_register_notifier();
ret = pci_register_driver(&velocity_driver);
if (ret < 0) ret_pci = pci_register_driver(&velocity_pci_driver);
ret_platform = platform_driver_register(&velocity_platform_driver);
/* if both_registers failed, remove the notifier */
if ((ret_pci < 0) && (ret_platform < 0)) {
velocity_unregister_notifier(); velocity_unregister_notifier();
return ret; return ret_pci;
}
return 0;
} }
/** /**
...@@ -3580,7 +3734,9 @@ static int __init velocity_init_module(void) ...@@ -3580,7 +3734,9 @@ static int __init velocity_init_module(void)
static void __exit velocity_cleanup_module(void) static void __exit velocity_cleanup_module(void)
{ {
velocity_unregister_notifier(); velocity_unregister_notifier();
pci_unregister_driver(&velocity_driver);
pci_unregister_driver(&velocity_pci_driver);
platform_driver_unregister(&velocity_platform_driver);
} }
module_init(velocity_init_module); module_init(velocity_init_module);
......
...@@ -1265,7 +1265,7 @@ struct velocity_context { ...@@ -1265,7 +1265,7 @@ struct velocity_context {
#define PHYID_VT3216_64BIT 0x000FC600UL #define PHYID_VT3216_64BIT 0x000FC600UL
#define PHYID_MARVELL_1000 0x01410C50UL #define PHYID_MARVELL_1000 0x01410C50UL
#define PHYID_MARVELL_1000S 0x01410C40UL #define PHYID_MARVELL_1000S 0x01410C40UL
#define PHYID_ICPLUS_IP101A 0x02430C54UL
#define PHYID_REV_ID_MASK 0x0000000FUL #define PHYID_REV_ID_MASK 0x0000000FUL
#define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK) #define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK)
...@@ -1437,6 +1437,7 @@ struct velocity_info { ...@@ -1437,6 +1437,7 @@ struct velocity_info {
struct device *dev; struct device *dev;
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device *netdev; struct net_device *netdev;
int no_eeprom;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u8 ip_addr[4]; u8 ip_addr[4];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment