spinlock_t lock;
+#ifdef SMC_CAN_USE_DATACS
+ u32 __iomem *datacs;
+#endif
+
#ifdef SMC_USE_PXA_DMA
/* DMA needs the physical address of the chip */
u_long physaddr;
#endif
+ void __iomem *base;
};
#if SMC_DEBUG > 0
*/
static void smc_reset(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int ctl, cfg;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
*/
static void smc_enable(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
int mask;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
*/
static void smc_shutdown(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
static inline void smc_rcv(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
unsigned int packet_number, status, packet_len;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
dev->name, packet_number, status,
packet_len, packet_len);
- if (unlikely(status & RS_ERRORS)) {
+ back:
+ if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
+ if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
+ /* accept VLAN packets */
+ status &= ~RS_TOOLONG;
+ goto back;
+ }
+ if (packet_len < 6) {
+ /* bloody hardware */
+ printk(KERN_ERR "%s: fubar (rxlen %u status %x\n",
+ dev->name, packet_len, status);
+ status |= RS_TOOSHORT;
+ }
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
lp->stats.rx_errors++;
* (2 bytes, possibly containing the payload odd byte).
* Furthermore, we add 2 bytes to allow rounding up to
* multiple of 4 bytes on 32 bit buses.
- * Ence packet_len - 6 + 2 + 2 + 2.
+ * Hence packet_len - 6 + 2 + 2 + 2.
*/
skb = dev_alloc_skb(packet_len);
if (unlikely(skb == NULL)) {
{
struct net_device *dev = (struct net_device *)data;
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
struct sk_buff *skb;
unsigned int packet_no, len;
unsigned char *buf;
static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
unsigned int numPages, poll_count, status;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
*/
static void smc_tx(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int saved_packet, packet_no, tx_status, pkt_len;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
static void smc_mii_out(struct net_device *dev, unsigned int val, int bits)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int mii_reg, mask;
mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO);
static unsigned int smc_mii_in(struct net_device *dev, int bits)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int mii_reg, mask, val;
mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO);
*/
static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int phydata;
SMC_SELECT_BANK(3);
static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
int phydata)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
SMC_SELECT_BANK(3);
static int smc_phy_fixed(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
int phyaddr = lp->mii.phy_id;
int bmcr, cfg1;
/*
* smc_phy_powerdown - powerdown phy
* @dev: net device
- * @phy: phy address
*
* Power down the specified PHY
*/
-static void smc_phy_powerdown(struct net_device *dev, int phy)
+static void smc_phy_powerdown(struct net_device *dev)
{
+ struct smc_local *lp = netdev_priv(dev);
unsigned int bmcr;
+ int phy = lp->mii.phy_id;
+
+ if (lp->phy_type == 0)
+ return;
+
+ /* We need to ensure that no calls to smc_phy_configure are
+ pending.
+
+ flush_scheduled_work() cannot be called because we are
+ running with the netlink semaphore held (from
+ devinet_ioctl()) and the pending work queue contains
+ linkwatch_event() (scheduled by netif_carrier_off()
+ above). linkwatch_event() also wants the netlink semaphore.
+ */
+ while(lp->work_pending)
+ schedule();
bmcr = smc_phy_read(dev, phy, MII_BMCR);
smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
static void smc_phy_check_media(struct net_device *dev, int init)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
/* duplex state has changed */
{
struct net_device *dev = data;
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
int phyaddr = lp->mii.phy_id;
int my_phy_caps; /* My PHY capabilities */
int my_ad_caps; /* My Advertised capabilities */
static void smc_10bt_check_media(struct net_device *dev, int init)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
unsigned int old_carrier, new_carrier;
old_carrier = netif_carrier_ok(dev) ? 1 : 0;
static void smc_eph_interrupt(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
unsigned int ctl;
smc_10bt_check_media(dev, 0);
static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
- unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
int status, mask, timeout, card_stats;
int saved_pointer;
static void smc_timeout(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
int status, mask, meminfo, fifo;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
static void smc_set_multicast_list(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = lp->base;
unsigned char multicast_table[8];
int update_multicast = 0;
/* clear everything */
smc_shutdown(dev);
- if (lp->phy_type != 0) {
- /* We need to ensure that no calls to
- smc_phy_configure are pending.
-
- flush_scheduled_work() cannot be called because we
- are running with the netlink semaphore held (from
- devinet_ioctl()) and the pending work queue
- contains linkwatch_event() (scheduled by
- netif_carrier_off() above). linkwatch_event() also
- wants the netlink semaphore.
- */
- while(lp->work_pending)
- schedule();
- smc_phy_powerdown(dev, lp->mii.phy_id);
- }
+ smc_phy_powerdown(dev);
if (lp->pending_tx_skb) {
dev_kfree_skb(lp->pending_tx_skb);
* I just deleted auto_irq.c, since it was never built...
* --jgarzik
*/
-static int __init smc_findirq(unsigned long ioaddr)
+static int __init smc_findirq(void __iomem *ioaddr)
{
int timeout = 20;
unsigned long cookie;
* o actually GRAB the irq.
* o GRAB the region
*/
-static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
+static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
{
struct smc_local *lp = netdev_priv(dev);
static int version_printed = 0;
if ((val & 0xFF) == 0x33) {
printk(KERN_WARNING
"%s: Detected possible byte-swapped interface"
- " at IOADDR 0x%lx\n", CARDNAME, ioaddr);
+ " at IOADDR %p\n", CARDNAME, ioaddr);
}
retval = -ENODEV;
goto err_out;
SMC_SELECT_BANK(1);
val = SMC_GET_BASE();
val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
- if ((ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val) {
- printk("%s: IOADDR %lx doesn't match configuration (%x).\n",
+ if (((unsigned long)ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val) { /*XXX: WTF? */
+ printk("%s: IOADDR %p doesn't match configuration (%x).\n",
CARDNAME, ioaddr, val);
}
version_string = chip_ids[ (revision_register >> 4) & 0xF];
if (!version_string || (revision_register & 0xff00) != 0x3300) {
/* I don't recognize this chip, so... */
- printk("%s: IO 0x%lx: Unrecognized revision register 0x%04x"
+ printk("%s: IO %p: Unrecognized revision register 0x%04x"
", Contact author.\n", CARDNAME,
ioaddr, revision_register);
printk("%s", version);
/* fill in some of the fields */
- dev->base_addr = ioaddr;
+ dev->base_addr = (unsigned long)ioaddr;
+ lp->base = ioaddr;
lp->version = revision_register & 0xff;
spin_lock_init(&lp->lock);
retval = register_netdev(dev);
if (retval == 0) {
/* now, print out the card info, in a short format.. */
- printk("%s: %s (rev %d) at %#lx IRQ %d",
+ printk("%s: %s (rev %d) at %p IRQ %d",
dev->name, version_string, revision_register & 0x0f,
- dev->base_addr, dev->irq);
+ lp->base, dev->irq);
if (dev->dma != (unsigned char)-1)
printk(" DMA %d", dev->dma);
return retval;
}
-static int smc_enable_device(unsigned long attrib_phys)
+static int smc_enable_device(struct platform_device *pdev)
{
unsigned long flags;
unsigned char ecor, ecsr;
- void *addr;
+ void __iomem *addr;
+ struct resource * res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+ if (!res)
+ return 0;
/*
* Map the attribute space. This is overkill, but clean.
*/
- addr = ioremap(attrib_phys, ATTRIB_SIZE);
+ addr = ioremap(res->start, ATTRIB_SIZE);
if (!addr)
return -ENOMEM;
return 0;
}
+static int smc_request_attrib(struct platform_device *pdev)
+{
+ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+
+ if (!res)
+ return 0;
+
+ if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))
+ return -EBUSY;
+
+ return 0;
+}
+
+static void smc_release_attrib(struct platform_device *pdev)
+{
+ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+
+ if (res)
+ release_mem_region(res->start, ATTRIB_SIZE);
+}
+
+#ifdef SMC_CAN_USE_DATACS
+static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+ struct smc_local *lp = netdev_priv(ndev);
+
+ if (!res)
+ return;
+
+ if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) {
+ printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME);
+ return;
+ }
+
+ lp->datacs = ioremap(res->start, SMC_DATA_EXTENT);
+}
+
+static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+ struct smc_local *lp = netdev_priv(ndev);
+ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+
+ if (lp->datacs)
+ iounmap(lp->datacs);
+
+ lp->datacs = NULL;
+
+ if (res)
+ release_mem_region(res->start, SMC_DATA_EXTENT);
+}
+#else
+static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) {}
+static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) {}
+#endif
+
/*
* smc_init(void)
* Input parameters:
{
struct platform_device *pdev = to_platform_device(dev);
struct net_device *ndev;
- struct resource *res, *ext = NULL;
- unsigned int *addr;
+ struct resource *res;
+ unsigned int __iomem *addr;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
goto out;
}
- /*
- * Request the regions.
- */
- if (!request_mem_region(res->start, SMC_IO_EXTENT, "smc91x")) {
+
+ if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
ret = -EBUSY;
goto out;
}
if (!ndev) {
printk("%s: could not allocate device.\n", CARDNAME);
ret = -ENOMEM;
- goto release_1;
+ goto out_release_io;
}
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, dev);
ndev->dma = (unsigned char)-1;
ndev->irq = platform_get_irq(pdev, 0);
- ext = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (ext) {
- if (!request_mem_region(ext->start, ATTRIB_SIZE, ndev->name)) {
- ret = -EBUSY;
- goto release_1;
- }
-
+ ret = smc_request_attrib(pdev);
+ if (ret)
+ goto out_free_netdev;
#if defined(CONFIG_SA1100_ASSABET)
- NCR_0 |= NCR_ENET_OSC_EN;
+ NCR_0 |= NCR_ENET_OSC_EN;
#endif
-
- ret = smc_enable_device(ext->start);
- if (ret)
- goto release_both;
- }
+ ret = smc_enable_device(pdev);
+ if (ret)
+ goto out_release_attrib;
addr = ioremap(res->start, SMC_IO_EXTENT);
if (!addr) {
ret = -ENOMEM;
- goto release_both;
+ goto out_release_attrib;
}
dev_set_drvdata(dev, ndev);
- ret = smc_probe(ndev, (unsigned long)addr);
- if (ret != 0) {
- dev_set_drvdata(dev, NULL);
- iounmap(addr);
- release_both:
- if (ext)
- release_mem_region(ext->start, ATTRIB_SIZE);
- free_netdev(ndev);
- release_1:
- release_mem_region(res->start, SMC_IO_EXTENT);
- out:
- printk("%s: not found (%d).\n", CARDNAME, ret);
- }
+ ret = smc_probe(ndev, addr);
+ if (ret != 0)
+ goto out_iounmap;
#ifdef SMC_USE_PXA_DMA
else {
struct smc_local *lp = netdev_priv(ndev);
}
#endif
+ smc_request_datacs(pdev, ndev);
+
+ return 0;
+
+ out_iounmap:
+ dev_set_drvdata(dev, NULL);
+ iounmap(addr);
+ out_release_attrib:
+ smc_release_attrib(pdev);
+ out_free_netdev:
+ free_netdev(ndev);
+ out_release_io:
+ release_mem_region(res->start, SMC_IO_EXTENT);
+ out:
+ printk("%s: not found (%d).\n", CARDNAME, ret);
+
return ret;
}
{
struct platform_device *pdev = to_platform_device(dev);
struct net_device *ndev = dev_get_drvdata(dev);
+ struct smc_local *lp = netdev_priv(ndev);
struct resource *res;
dev_set_drvdata(dev, NULL);
if (ndev->dma != (unsigned char)-1)
pxa_free_dma(ndev->dma);
#endif
- iounmap((void *)ndev->base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res)
- release_mem_region(res->start, ATTRIB_SIZE);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(lp->base);
+
+ smc_release_datacs(pdev,ndev);
+ smc_release_attrib(pdev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+ if (!res)
+ platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, SMC_IO_EXTENT);
free_netdev(ndev);
return 0;
}
-static int smc_drv_suspend(struct device *dev, u32 state, u32 level)
+static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level)
{
struct net_device *ndev = dev_get_drvdata(dev);
if (netif_running(ndev)) {
netif_device_detach(ndev);
smc_shutdown(ndev);
+ smc_phy_powerdown(ndev);
}
}
return 0;
if (ndev && level == RESUME_ENABLE) {
struct smc_local *lp = netdev_priv(ndev);
-
- if (pdev->num_resources == 3)
- smc_enable_device(pdev->resource[2].start);
+ smc_enable_device(pdev);
if (netif_running(ndev)) {
smc_reset(ndev);
smc_enable(ndev);