DM9000: Add support for DM9000A and DM9000B chips
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>
This commit is contained in:
@@ -85,6 +85,16 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
|
|||||||
* these two devices.
|
* 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 ------------------------------- */
|
/* Structure/enum declaration ------------------------------- */
|
||||||
typedef struct board_info {
|
typedef struct board_info {
|
||||||
|
|
||||||
@@ -98,9 +108,11 @@ typedef struct board_info {
|
|||||||
u16 dbug_cnt;
|
u16 dbug_cnt;
|
||||||
u8 io_mode; /* 0:word, 2:byte */
|
u8 io_mode; /* 0:word, 2:byte */
|
||||||
u8 phy_addr;
|
u8 phy_addr;
|
||||||
|
u8 imr_all;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int in_suspend :1;
|
unsigned int in_suspend :1;
|
||||||
|
|
||||||
|
enum dm9000_type type;
|
||||||
int debug_level;
|
int debug_level;
|
||||||
|
|
||||||
void (*inblk)(void __iomem *port, void *data, int length);
|
void (*inblk)(void __iomem *port, void *data, int length);
|
||||||
@@ -302,6 +314,7 @@ static void dm9000_set_io(struct board_info *db, int byte_width)
|
|||||||
|
|
||||||
static void dm9000_schedule_poll(board_info_t *db)
|
static void dm9000_schedule_poll(board_info_t *db)
|
||||||
{
|
{
|
||||||
|
if (db->type == TYPE_DM9000E)
|
||||||
schedule_delayed_work(&db->phy_poll, HZ * 2);
|
schedule_delayed_work(&db->phy_poll, HZ * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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)
|
#define res_size(_r) (((_r)->end - (_r)->start) + 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -665,6 +689,23 @@ dm9000_probe(struct platform_device *pdev)
|
|||||||
goto out;
|
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 */
|
/* from this point we assume that we have found a DM9000 */
|
||||||
|
|
||||||
/* driver system function */
|
/* driver system function */
|
||||||
@@ -715,8 +756,9 @@ dm9000_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
DECLARE_MAC_BUF(mac);
|
DECLARE_MAC_BUF(mac);
|
||||||
printk("%s: dm9000 at %p,%p IRQ %d MAC: %s (%s)\n",
|
printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n",
|
||||||
ndev->name, db->io_addr, db->io_data, ndev->irq,
|
ndev->name, dm9000_type_to_char(db->type),
|
||||||
|
db->io_addr, db->io_data, ndev->irq,
|
||||||
print_mac(mac, ndev->dev_addr), mac_src);
|
print_mac(mac, ndev->dev_addr), mac_src);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -778,6 +820,7 @@ static void
|
|||||||
dm9000_init_dm9000(struct net_device *dev)
|
dm9000_init_dm9000(struct net_device *dev)
|
||||||
{
|
{
|
||||||
board_info_t *db = (board_info_t *) dev->priv;
|
board_info_t *db = (board_info_t *) dev->priv;
|
||||||
|
unsigned int imr;
|
||||||
|
|
||||||
dm9000_dbg(db, 1, "entering %s\n", __func__);
|
dm9000_dbg(db, 1, "entering %s\n", __func__);
|
||||||
|
|
||||||
@@ -804,8 +847,14 @@ dm9000_init_dm9000(struct net_device *dev)
|
|||||||
/* Set address filter table */
|
/* Set address filter table */
|
||||||
dm9000_hash_table(dev);
|
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 */
|
/* Enable TX/RX interrupt mask */
|
||||||
iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
|
iow(db, DM9000_IMR, imr);
|
||||||
|
|
||||||
/* Init Driver variable */
|
/* Init Driver variable */
|
||||||
db->tx_pkt_cnt = 0;
|
db->tx_pkt_cnt = 0;
|
||||||
@@ -962,8 +1011,15 @@ dm9000_interrupt(int irq, void *dev_id)
|
|||||||
if (int_status & ISR_PTS)
|
if (int_status & ISR_PTS)
|
||||||
dm9000_tx_done(dev, db);
|
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 */
|
/* 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 */
|
/* Restore previous register address */
|
||||||
writeb(reg_save, db->io_addr);
|
writeb(reg_save, db->io_addr);
|
||||||
|
@@ -45,6 +45,9 @@
|
|||||||
#define DM9000_CHIPR 0x2C
|
#define DM9000_CHIPR 0x2C
|
||||||
#define DM9000_SMCR 0x2F
|
#define DM9000_SMCR 0x2F
|
||||||
|
|
||||||
|
#define CHIPR_DM9000A 0x19
|
||||||
|
#define CHIPR_DM9000B 0x1B
|
||||||
|
|
||||||
#define DM9000_MRCMDX 0xF0
|
#define DM9000_MRCMDX 0xF0
|
||||||
#define DM9000_MRCMD 0xF2
|
#define DM9000_MRCMD 0xF2
|
||||||
#define DM9000_MRRL 0xF4
|
#define DM9000_MRRL 0xF4
|
||||||
@@ -131,5 +134,13 @@
|
|||||||
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
|
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
|
||||||
#define DM9000_PKT_MAX 1536 /* Received packet max size */
|
#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_ */
|
#endif /* _DM9000X_H_ */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user