-/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
+/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
- "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+ "myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <net/dst.h>
#include <net/arp.h>
#include <net/ipv6.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/auxio.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
-#include <asm/checksum.h>
#include "myri_sbus.h"
#include "myri_code.h"
#define DHDR(x)
#endif
-#ifdef MODULE
-static struct myri_eth *root_myri_dev;
-#endif
-
-static void myri_reset_off(unsigned long lp, unsigned long cregs)
+static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
sbus_writel(0, lp + LANAI_EIMASK);
sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL);
}
-static void myri_reset_on(unsigned long cregs)
+static void myri_reset_on(void __iomem *cregs)
{
/* Enable RESET function. */
sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL);
sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
}
-static void myri_disable_irq(unsigned long lp, unsigned long cregs)
+static void myri_disable_irq(void __iomem *lp, void __iomem *cregs)
{
sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
sbus_writel(0, lp + LANAI_EIMASK);
sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT);
}
-static void myri_enable_irq(unsigned long lp, unsigned long cregs)
+static void myri_enable_irq(void __iomem *lp, void __iomem *cregs)
{
sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL);
sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK);
static inline void bang_the_chip(struct myri_eth *mp)
{
- struct myri_shmem *shmem = mp->shmem;
- unsigned long cregs = mp->cregs;
+ struct myri_shmem __iomem *shmem = mp->shmem;
+ void __iomem *cregs = mp->cregs;
sbus_writel(1, &shmem->send);
sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);
static int myri_do_handshake(struct myri_eth *mp)
{
- struct myri_shmem *shmem = mp->shmem;
- unsigned long cregs = mp->cregs;
- struct myri_channel *chan = &shmem->channel;
+ struct myri_shmem __iomem *shmem = mp->shmem;
+ void __iomem *cregs = mp->cregs;
+ struct myri_channel __iomem *chan = &shmem->channel;
int tick = 0;
DET(("myri_do_handshake: "));
return 0;
}
-static int myri_load_lanai(struct myri_eth *mp)
+static int __devinit myri_load_lanai(struct myri_eth *mp)
{
struct net_device *dev = mp->dev;
- struct myri_shmem *shmem = mp->shmem;
- unsigned char *rptr;
+ struct myri_shmem __iomem *shmem = mp->shmem;
+ void __iomem *rptr;
int i;
myri_disable_irq(mp->lregs, mp->cregs);
myri_reset_on(mp->cregs);
- rptr = (unsigned char *) mp->lanai;
+ rptr = mp->lanai;
for (i = 0; i < mp->eeprom.ramsz; i++)
- sbus_writeb(0, &rptr[i]);
+ sbus_writeb(0, rptr + i);
if (mp->eeprom.cpuvers >= CPUVERS_3_0)
sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL);
/* Load executable code. */
for (i = 0; i < sizeof(lanai4_code); i++)
- sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]);
+ sbus_writeb(lanai4_code[i], rptr + (lanai4_code_off * 2) + i);
/* Load data segment. */
for (i = 0; i < sizeof(lanai4_data); i++)
- sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]);
+ sbus_writeb(lanai4_data[i], rptr + (lanai4_data_off * 2) + i);
/* Set device address. */
sbus_writeb(0, &shmem->addr[0]);
static void myri_clean_rings(struct myri_eth *mp)
{
- struct sendq *sq = mp->sq;
- struct recvq *rq = mp->rq;
+ struct sendq __iomem *sq = mp->sq;
+ struct recvq __iomem *rq = mp->rq;
int i;
sbus_writel(0, &rq->tail);
sbus_writel(0, &rq->head);
for (i = 0; i < (RX_RING_SIZE+1); i++) {
if (mp->rx_skbs[i] != NULL) {
- struct myri_rxd *rxd = &rq->myri_rxd[i];
+ struct myri_rxd __iomem *rxd = &rq->myri_rxd[i];
u32 dma_addr;
dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
for (i = 0; i < TX_RING_SIZE; i++) {
if (mp->tx_skbs[i] != NULL) {
struct sk_buff *skb = mp->tx_skbs[i];
- struct myri_txd *txd = &sq->myri_txd[i];
+ struct myri_txd __iomem *txd = &sq->myri_txd[i];
u32 dma_addr;
dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
static void myri_init_rings(struct myri_eth *mp, int from_irq)
{
- struct recvq *rq = mp->rq;
- struct myri_rxd *rxd = &rq->myri_rxd[0];
+ struct recvq __iomem *rq = mp->rq;
+ struct myri_rxd __iomem *rxd = &rq->myri_rxd[0];
struct net_device *dev = mp->dev;
- int gfp_flags = GFP_KERNEL;
+ gfp_t gfp_flags = GFP_KERNEL;
int i;
if (from_irq || in_interrupt())
static void myri_tx(struct myri_eth *mp, struct net_device *dev)
{
- struct sendq *sq = mp->sq;
+ struct sendq __iomem *sq= mp->sq;
int entry = mp->tx_old;
int limit = sbus_readl(&sq->head);
mp->tx_old = entry;
}
-/* Determine the packet's protocol ID. The rule here is that we
+/* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
-static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
-
+
skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);
skb_pull(skb, dev->hard_header_len);
- eth = skb->mac.ethernet;
-
+ eth = eth_hdr(skb);
+
#ifdef DEBUG_HEADER
DHDR(("myri_type_trans: "));
dump_ehdr(eth);
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
-
+
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
-
+
rawp = skb->data;
-
+
/* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
*/
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
-
+
/* Real 802.2 LLC */
return htons(ETH_P_802_2);
}
static void myri_rx(struct myri_eth *mp, struct net_device *dev)
{
- struct recvq *rq = mp->rq;
- struct recvq *rqa = mp->rqack;
+ struct recvq __iomem *rq = mp->rq;
+ struct recvq __iomem *rqa = mp->rqack;
int entry = sbus_readl(&rqa->head);
int limit = sbus_readl(&rqa->tail);
int drops;
drops = 0;
DRX(("\n"));
while (entry != limit) {
- struct myri_rxd *rxdack = &rqa->myri_rxd[entry];
+ struct myri_rxd __iomem *rxdack = &rqa->myri_rxd[entry];
u32 csum = sbus_readl(&rxdack->csum);
int len = sbus_readl(&rxdack->myri_scatters[0].len);
int index = sbus_readl(&rxdack->ctx);
- struct myri_rxd *rxd = &rq->myri_rxd[rq->tail];
+ struct myri_rxd __iomem *rxd = &rq->myri_rxd[sbus_readl(&rq->tail)];
struct sk_buff *skb = mp->rx_skbs[index];
/* Ack it. */
}
}
-static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t myri_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct myri_eth *mp = (struct myri_eth *) dev->priv;
- unsigned long lregs = mp->lregs;
- struct myri_channel *chan = &mp->shmem->channel;
+ void __iomem *lregs = mp->lregs;
+ struct myri_channel __iomem *chan = &mp->shmem->channel;
unsigned long flags;
u32 status;
int handled = 0;
static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct myri_eth *mp = (struct myri_eth *) dev->priv;
- struct sendq *sq = mp->sq;
- struct myri_txd *txd;
+ struct sendq __iomem *sq = mp->sq;
+ struct myri_txd __iomem *txd;
unsigned long flags;
unsigned int head, tail;
int len, entry;
return 0;
}
-/* Create the MyriNet MAC header for an arbitrary protocol layer
+/* Create the MyriNet MAC header for an arbitrary protocol layer
*
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp)
/* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
* in here instead. It is up to the 802.2 layer to carry protocol information.
*/
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
eth->h_dest[i] = 0;
return(dev->hard_header_len);
}
-
+
if (daddr) {
memcpy(eth->h_dest, daddr, dev->addr_len);
return dev->hard_header_len;
#endif
default:
- printk(KERN_DEBUG
- "%s: unable to resolve type %X addresses.\n",
+ printk(KERN_DEBUG
+ "%s: unable to resolve type %X addresses.\n",
dev->name, (int)eth->h_proto);
-
+
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return 0;
break;
}
- return 0;
+ return 0;
}
int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
}
#endif
-static int __init myri_ether_init(struct sbus_dev *sdev, int num)
+static int __devinit myri_ether_init(struct sbus_dev *sdev)
{
+ static int num;
static unsigned version_printed;
struct net_device *dev;
struct myri_eth *mp;
if (version_printed++ == 0)
printk(version);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
mp = (struct myri_eth *) dev->priv;
spin_lock_init(&mp->irq_lock);
mp->myri_sdev = sdev;
printk("MyriCOM: Cannot map MyriCOM registers.\n");
goto err;
}
- mp->lanai = (unsigned short *) (mp->regs + (256 * 1024));
- mp->lanai3 = (unsigned int *) mp->lanai;
- mp->lregs = (unsigned long) &mp->lanai[0x10000];
+ mp->lanai = mp->regs + (256 * 1024);
+ mp->lregs = mp->lanai + (0x10000 * 2);
} else {
DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
PAGE_SIZE, "MyriCOM Control Regs");
mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
PAGE_SIZE, "MyriCOM LANAI Regs");
- mp->lanai = (unsigned short *)
+ mp->lanai =
sbus_ioremap(&sdev->resource[0], (512 * 1024),
mp->eeprom.ramsz, "MyriCOM SRAM");
- mp->lanai3 = (unsigned int *) mp->lanai;
}
- DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n",
- mp->cregs, mp->lregs, mp->lanai, mp->lanai3));
+ DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
+ mp->cregs, mp->lregs, mp->lanai));
if (mp->eeprom.cpuvers >= CPUVERS_4_0)
mp->shmem_base = 0xf000;
DET(("Shared memory base is %04x, ", mp->shmem_base));
- mp->shmem = (struct myri_shmem *) &mp->lanai[mp->shmem_base];
+ mp->shmem = (struct myri_shmem __iomem *)
+ (mp->lanai + (mp->shmem_base * 2));
DET(("shmem mapped at %p\n", mp->shmem));
mp->rqack = &mp->shmem->channel.recvqa;
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
if (request_irq(dev->irq, &myri_interrupt,
- SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
+ IRQF_SHARED, "MyriCOM Ethernet", (void *) dev)) {
printk("MyriCOM: Cannot register interrupt handler.\n");
goto err;
}
goto err_free_irq;
}
-#ifdef MODULE
- mp->next_module = root_myri_dev;
- root_myri_dev = mp;
-#endif
+ dev_set_drvdata(&sdev->ofdev.dev, mp);
+
+ num++;
printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
return -ENODEV;
}
-static int __init myri_sbus_match(struct sbus_dev *sdev)
-{
- char *name = sdev->prom_name;
- if (!strcmp(name, "MYRICOM,mlanai") ||
- !strcmp(name, "myri"))
- return 1;
+static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- return 0;
+ return myri_ether_init(sdev);
}
-static int __init myri_sbus_probe(void)
+static int __devexit myri_sbus_remove(struct of_device *dev)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = 0;
- static int called;
- int cards = 0, v;
+ struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = mp->dev;
-#ifdef MODULE
- root_myri_dev = NULL;
-#endif
+ unregister_netdevice(net_dev);
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if (myri_sbus_match(sdev)) {
- cards++;
- DET(("Found myricom myrinet as %s\n", sdev->prom_name));
- if ((v = myri_ether_init(sdev, (cards - 1))))
- return v;
- }
- }
+ free_irq(net_dev->irq, net_dev);
+
+ if (mp->eeprom.cpuvers < CPUVERS_4_0) {
+ sbus_iounmap(mp->regs, mp->reg_size);
+ } else {
+ sbus_iounmap(mp->cregs, PAGE_SIZE);
+ sbus_iounmap(mp->lregs, (256 * 1024));
+ sbus_iounmap(mp->lanai, (512 * 1024));
}
- if (!cards)
- return -ENODEV;
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit myri_sbus_cleanup(void)
+static struct of_device_id myri_sbus_match[] = {
+ {
+ .name = "MYRICOM,mlanai",
+ },
+ {
+ .name = "myri",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, myri_sbus_match);
+
+static struct of_platform_driver myri_sbus_driver = {
+ .name = "myri",
+ .match_table = myri_sbus_match,
+ .probe = myri_sbus_probe,
+ .remove = __devexit_p(myri_sbus_remove),
+};
+
+static int __init myri_sbus_init(void)
+{
+ return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit myri_sbus_exit(void)
{
-#ifdef MODULE
- while (root_myri_dev) {
- struct myri_eth *next = root_myri_dev->next_module;
-
- unregister_netdev(root_myri_dev->dev);
- /* this will also free the co-allocated 'root_myri_dev' */
- free_netdev(root_myri_dev->dev);
- root_myri_dev = next;
- }
-#endif /* MODULE */
+ of_unregister_driver(&myri_sbus_driver);
}
-module_init(myri_sbus_probe);
-module_exit(myri_sbus_cleanup);
+module_init(myri_sbus_init);
+module_exit(myri_sbus_exit);
+
MODULE_LICENSE("GPL");