module_param(watchdog, int, 0400);
MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+/* DM9000 register address locking.
+ *
+ * The DM9000 uses an address register to control where data written
+ * to the data register goes. This means that the address register
+ * must be preserved over interrupts or similar calls.
+ *
+ * During interrupt and other critical calls, a spinlock is used to
+ * protect the system, but the calls themselves save the address
+ * in the address register in case they are interrupting another
+ * access to the device.
+ *
+ * For general accesses a lock is provided so that calls which are
+ * allowed to sleep are serialised so that the address register does
+ * not need to be saved. This lock also serves to serialise access
+ * to the EEPROM and PHY access registers which are shared between
+ * these two devices.
+ */
+
/* Structure/enum declaration ------------------------------- */
typedef struct board_info {
struct resource *data_req;
struct resource *irq_res;
+ struct mutex addr_lock; /* phy and eeprom access lock */
+
spinlock_t lock;
struct mii_if_info mii;
static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
board_info_t *dm = to_dm9000_board(dev);
- unsigned long flags;
- spin_lock_irqsave(&dm->lock, flags);
mii_ethtool_gset(&dm->mii, cmd);
- spin_lock_irqsave(&dm->lock, flags);
-
return 0;
}
static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
board_info_t *dm = to_dm9000_board(dev);
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&dm->lock, flags);
- rc = mii_ethtool_sset(&dm->mii, cmd);
- spin_lock_irqsave(&dm->lock, flags);
- return rc;
+ return mii_ethtool_sset(&dm->mii, cmd);
}
static int dm9000_nway_reset(struct net_device *dev)
db->dev = &pdev->dev;
spin_lock_init(&db->lock);
+ mutex_init(&db->addr_lock);
if (pdev->num_resources < 2) {
ret = -ENODEV;
* Read a word data from EEPROM
*/
static void
-dm9000_read_eeprom(board_info_t * db, int offset, unsigned char *to)
+dm9000_read_eeprom(board_info_t *db, int offset, unsigned char *to)
{
+ mutex_lock(&db->addr_lock);
+
iow(db, DM9000_EPAR, offset);
iow(db, DM9000_EPCR, EPCR_ERPRR);
mdelay(8); /* according to the datasheet 200us should be enough,
to[0] = ior(db, DM9000_EPDRL);
to[1] = ior(db, DM9000_EPDRH);
+
+ mutex_unlock(&db->addr_lock);
}
#ifdef DM9000_PROGRAM_EEPROM
static void
write_srom_word(board_info_t * db, int offset, u16 val)
{
+ mutex_lock(&db->addr_lock);
+
iow(db, DM9000_EPAR, offset);
iow(db, DM9000_EPDRH, ((val >> 8) & 0xff));
iow(db, DM9000_EPDRL, (val & 0xff));
iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
mdelay(8); /* same shit */
iow(db, DM9000_EPCR, 0);
+
+ mutex_unlock(&db->addr_lock);
}
/*
unsigned int reg_save;
int ret;
+ mutex_lock(&db->addr_lock);
+
spin_lock_irqsave(&db->lock,flags);
/* Save previous register address */
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock,flags);
+ mutex_unlock(&db->addr_lock);
return ret;
}
unsigned long flags;
unsigned long reg_save;
+ mutex_lock(&db->addr_lock);
+
spin_lock_irqsave(&db->lock,flags);
/* Save previous register address */
iow(db, DM9000_EPCR, 0xa); /* Issue phyxcer write command */
writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock,flags);
+ spin_unlock_irqrestore(&db->lock, flags);
dm9000_msleep(db, 1); /* Wait write complete */
/* restore the previous address */
writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock,flags);
+ spin_unlock_irqrestore(&db->lock, flags);
+ mutex_unlock(&db->addr_lock);
}
static int