Skip to content

Commit

Permalink
DM9000: Add support for DM9000A and DM9000B chips
Browse files Browse the repository at this point in the history
Add support for both the DM9000A and DM9000B versions of
the DM9000 networking chip. This includes adding support
for the Link-Change IRQ which is used instead of polling
the PHY every 2 seconds.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
Ben Dooks authored and Jeff Garzik committed Jun 25, 2008
1 parent da3854f commit 6d406b3
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 5 deletions.
66 changes: 61 additions & 5 deletions drivers/net/dm9000.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
* these two devices.
*/

/* The driver supports the original DM9000E, and now the two newer
* devices, DM9000A and DM9000B.
*/

enum dm9000_type {
TYPE_DM9000E, /* original DM9000 */
TYPE_DM9000A,
TYPE_DM9000B
};

/* Structure/enum declaration ------------------------------- */
typedef struct board_info {

Expand All @@ -98,9 +108,11 @@ typedef struct board_info {
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
u8 imr_all;
unsigned int flags;
unsigned int in_suspend :1;

enum dm9000_type type;
int debug_level;

void (*inblk)(void __iomem *port, void *data, int length);
Expand Down Expand Up @@ -302,7 +314,8 @@ static void dm9000_set_io(struct board_info *db, int byte_width)

static void dm9000_schedule_poll(board_info_t *db)
{
schedule_delayed_work(&db->phy_poll, HZ * 2);
if (db->type == TYPE_DM9000E)
schedule_delayed_work(&db->phy_poll, HZ * 2);
}

/* Our watchdog timed out. Called by the networking layer */
Expand Down Expand Up @@ -516,6 +529,17 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
}
}

static unsigned char dm9000_type_to_char(enum dm9000_type type)
{
switch (type) {
case TYPE_DM9000E: return 'e';
case TYPE_DM9000A: return 'a';
case TYPE_DM9000B: return 'b';
}

return '?';
}

#define res_size(_r) (((_r)->end - (_r)->start) + 1)

/*
Expand Down Expand Up @@ -665,6 +689,23 @@ dm9000_probe(struct platform_device *pdev)
goto out;
}

/* Identify what type of DM9000 we are working on */

id_val = ior(db, DM9000_CHIPR);
dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);

switch (id_val) {
case CHIPR_DM9000A:
db->type = TYPE_DM9000A;
break;
case CHIPR_DM9000B:
db->type = TYPE_DM9000B;
break;
default:
dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
db->type = TYPE_DM9000E;
}

/* from this point we assume that we have found a DM9000 */

/* driver system function */
Expand Down Expand Up @@ -715,8 +756,9 @@ dm9000_probe(struct platform_device *pdev)

if (ret == 0) {
DECLARE_MAC_BUF(mac);
printk("%s: dm9000 at %p,%p IRQ %d MAC: %s (%s)\n",
ndev->name, db->io_addr, db->io_data, ndev->irq,
printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n",
ndev->name, dm9000_type_to_char(db->type),
db->io_addr, db->io_data, ndev->irq,
print_mac(mac, ndev->dev_addr), mac_src);
}
return 0;
Expand Down Expand Up @@ -778,6 +820,7 @@ static void
dm9000_init_dm9000(struct net_device *dev)
{
board_info_t *db = (board_info_t *) dev->priv;
unsigned int imr;

dm9000_dbg(db, 1, "entering %s\n", __func__);

Expand All @@ -804,8 +847,14 @@ dm9000_init_dm9000(struct net_device *dev)
/* Set address filter table */
dm9000_hash_table(dev);

imr = IMR_PAR | IMR_PTM | IMR_PRM;
if (db->type != TYPE_DM9000E)
imr |= IMR_LNKCHNG;

db->imr_all = imr;

/* Enable TX/RX interrupt mask */
iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
iow(db, DM9000_IMR, imr);

/* Init Driver variable */
db->tx_pkt_cnt = 0;
Expand Down Expand Up @@ -962,8 +1011,15 @@ dm9000_interrupt(int irq, void *dev_id)
if (int_status & ISR_PTS)
dm9000_tx_done(dev, db);

if (db->type != TYPE_DM9000E) {
if (int_status & ISR_LNKCHNG) {
/* fire a link-change request */
schedule_delayed_work(&db->phy_poll, 1);
}
}

/* Re-enable interrupt mask */
iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
iow(db, DM9000_IMR, db->imr_all);

/* Restore previous register address */
writeb(reg_save, db->io_addr);
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/dm9000.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
#define DM9000_CHIPR 0x2C
#define DM9000_SMCR 0x2F

#define CHIPR_DM9000A 0x19
#define CHIPR_DM9000B 0x1B

#define DM9000_MRCMDX 0xF0
#define DM9000_MRCMD 0xF2
#define DM9000_MRRL 0xF4
Expand Down Expand Up @@ -131,5 +134,13 @@
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
#define DM9000_PKT_MAX 1536 /* Received packet max size */

/* DM9000A / DM9000B definitions */

#define IMR_LNKCHNG (1<<5)
#define IMR_UNDERRUN (1<<4)

#define ISR_LNKCHNG (1<<5)
#define ISR_UNDERRUN (1<<4)

#endif /* _DM9000X_H_ */

0 comments on commit 6d406b3

Please sign in to comment.