diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 4db1088..1cdfe0c 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -641,10 +641,18 @@
 #define EFUSE_CTRL			0x0580
 #define EFUSE_CTRL_ADDRESS_IN		FIELD32(0x03fe0000)
 #define EFUSE_CTRL_MODE			FIELD32(0x000000c0)
+#define EFUSE_CTRL_ADDRESS_OUT		FIELD32(0x0000003f)
 #define EFUSE_CTRL_KICK			FIELD32(0x40000000)
 #define EFUSE_CTRL_PRESENT		FIELD32(0x80000000)
 
 /*
+ * EFUSE MODE selection
+ */
+#define EFUSE_CTRL_MODE_READ_VIRTUAL    0
+#define EFUSE_CTRL_MODE_READ_PHYSICAL   1
+#define EFUSE_CTRL_MODE_WRITE_PHYSICAL  3
+
+/*
  * EFUSE_DATA0
  */
 #define EFUSE_DATA0			0x0590
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 197b446..f882a93 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -4574,7 +4574,8 @@ int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
 
-static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
+static u8 rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+			    unsigned int addr, int physical)
 {
 	u32 reg;
 	u16 efuse_ctrl_reg;
@@ -4582,6 +4583,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
 	u16 efuse_data1_reg;
 	u16 efuse_data2_reg;
 	u16 efuse_data3_reg;
+	u8 physaddr;
 
 	if (rt2x00_rt(rt2x00dev, RT3290)) {
 		efuse_ctrl_reg = EFUSE_CTRL_3290;
@@ -4599,36 +4601,193 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, &reg);
-	rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
-	rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
+	rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, addr);
+	rt2x00_set_field32(&reg, EFUSE_CTRL_MODE,
+			   physical ? EFUSE_CTRL_MODE_READ_PHYSICAL :
+			   EFUSE_CTRL_MODE_READ_VIRTUAL);
 	rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
 	rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg);
 
 	/* Wait until the EEPROM has been loaded */
 	rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, &reg);
+
+	/* Get the physical block mapping */
+	physaddr = rt2x00_get_field32(reg, EFUSE_CTRL_ADDRESS_OUT);
+
+	/* If we have no mapping for this address, don't bother reading. */
+	if (!physical && physaddr == 0x3f) {
+		memset(eeprom, 0xff, 16);
+		goto done;
+	}
+
 	/* Apparently the data is read from end to start */
 	rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, &reg);
 	/* The returned value is in CPU order, but eeprom is le */
-	*(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+	*(u32 *)&eeprom[0] = cpu_to_le32(reg);
 	rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, &reg);
-	*(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
+	*(u32 *)&eeprom[2] = cpu_to_le32(reg);
 	rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, &reg);
-	*(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
+	*(u32 *)&eeprom[4] = cpu_to_le32(reg);
 	rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, &reg);
-	*(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
+	*(u32 *)&eeprom[6] = cpu_to_le32(reg);
 
+done:
 	mutex_unlock(&rt2x00dev->csr_mutex);
+
+	return physaddr;
 }
 
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+			      const u16 length)
 {
 	unsigned int i;
+	u8 addr;
 
-	for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
-		rt2800_efuse_read(rt2x00dev, i);
+	for (i = 0; i < length / sizeof(u16); i += 8) {
+		addr = rt2800_efuse_read(rt2x00dev, eeprom + i, i, 0);
+		printk(KERN_INFO "efuse @ %x: physaddr %x\n", i * 2, addr);
+	}
 }
 EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
 
+static void rt2800_efuse_write_phys(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+				    unsigned int addr)
+
+{
+	u32 reg;
+	u16 efuse_ctrl_reg;
+	u16 efuse_data0_reg;
+	u16 efuse_data1_reg;
+	u16 efuse_data2_reg;
+	u16 efuse_data3_reg;
+
+	if (rt2x00_rt(rt2x00dev, RT3290)) {
+		efuse_ctrl_reg = EFUSE_CTRL_3290;
+		efuse_data0_reg = EFUSE_DATA0_3290;
+		efuse_data1_reg = EFUSE_DATA1_3290;
+		efuse_data2_reg = EFUSE_DATA2_3290;
+		efuse_data3_reg = EFUSE_DATA3_3290;
+	} else {
+		efuse_ctrl_reg = EFUSE_CTRL;
+		efuse_data0_reg = EFUSE_DATA0;
+		efuse_data1_reg = EFUSE_DATA1;
+		efuse_data2_reg = EFUSE_DATA2;
+		efuse_data3_reg = EFUSE_DATA3;
+	}
+	mutex_lock(&rt2x00dev->csr_mutex);
+
+	/* Apparently the data is written from end to start */
+	/* And the data needs to be in CPU order (eeprom is LE) */
+	rt2800_register_write_lock(rt2x00dev, efuse_data3_reg, le32_to_cpu(*(u32 *)&eeprom[0]));
+	rt2800_register_write_lock(rt2x00dev, efuse_data2_reg, le32_to_cpu(*(u32 *)&eeprom[2]));
+	rt2800_register_write_lock(rt2x00dev, efuse_data1_reg, le32_to_cpu(*(u32 *)&eeprom[4]));
+	rt2800_register_write_lock(rt2x00dev, efuse_data0_reg, le32_to_cpu(*(u32 *)&eeprom[6]));
+
+	rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, &reg);
+	rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, addr);
+	rt2x00_set_field32(&reg, EFUSE_CTRL_MODE,
+			   EFUSE_CTRL_MODE_WRITE_PHYSICAL);
+	rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
+	rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg);
+
+	/* Wait until the EEPROM has been written */
+	rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, &reg);
+
+	mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+void rt2800_write_eeprom_efuse(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+			       const u16 length)
+{
+	unsigned int i, j;
+	u16 startblock, endblock;
+	u8 map[64], blocks;
+	u8 map_update = 0;
+
+	endblock = 0x2fc; // based on device
+	startblock = 0x2d0; // based on device
+	blocks = 45; // based on device ( == startblock /16 )
+
+	/* Read in block map */
+	for (i = startblock ; i < endblock ; i += 16) {
+		u32 temp[4];
+		rt2800_efuse_read(rt2x00dev, (u16 *)temp, i>>1, 1);
+		for (j = 0 ; j < 4 ; j++)
+			temp[j] = cpu_to_le32(temp[j]);
+		memcpy(map + (i - startblock), temp, sizeof(temp));
+	}
+
+	/* Figure out what's changed and write it */
+	for (i = 0; i < length / sizeof(u16); i += 8) {
+		u16 temp[8];
+		u8 physblock;
+		u8 newmap = 0;
+
+		physblock = rt2800_efuse_read(rt2x00dev, temp, i, 0);
+		/* Don't bother if it's not been altered. */
+		if (!memcmp(eeprom + i, temp, sizeof(temp)))
+			continue;
+
+		printk(KERN_INFO "eFuse altered @ %02x, block 0x%02x\n",
+		       i * 2, physblock);
+
+	retry:
+		/* Find a new block if necessary */
+		if (physblock == 0x3f) {
+			for (j = blocks - 1; j >= 0; j--)
+				if (map[j] == 0)
+					break;
+			if (j < 0) {
+				printk(KERN_WARNING "No available eFuse blocks, aborting!\n");
+				return;
+			}
+			physblock = j;
+			newmap = 1;
+			printk(KERN_INFO "Allocating new eFuse block 0x%x\n", physblock);
+		}
+		/* Write updated data to eFuse */
+		rt2800_efuse_write_phys(rt2x00dev, eeprom + i, physblock << 3);
+
+		/* Perform readback test to make sure it "took" */
+		rt2800_efuse_read(rt2x00dev, temp, physblock << 3, 1);
+		if (memcmp(eeprom + i, temp, sizeof(temp))) {
+			printk(KERN_INFO "Block 0x%x readback failed -- marking invalid.\n", physblock);
+			/* Invalidate existing map entry */
+			for (j = 0; j < 8 ; j++) {
+				if (!(map[physblock] & (1 << j))) {
+					map[physblock] |= 1 << j;
+					break;
+				}
+			}
+			map_update = 1;
+			physblock = 0x3f;
+			goto retry;
+		}
+
+		/* Update map */
+		if (newmap) {
+			u8 addr = i >> 3;
+			/* Generate parity */
+			addr |= ((~((addr & 0x01) ^ ( addr >> 1 & 0x01) ^  (addr >> 2 & 0x01) ^  (addr >> 3 & 0x01))) << 6) & 0x40;
+			addr |= ((~( (addr >> 2 & 0x01) ^ (addr >> 3 & 0x01) ^ (addr >> 4 & 0x01) ^ ( addr >> 5 & 0x01))) << 7) & 0x80;
+			map[physblock] = addr;
+			map_update = 1;
+		}
+	}
+
+	if (map_update) {
+		/* Write updated map */
+		for (i = startblock ; i < endblock ; i += 16) {
+			u32 temp[4];
+			memcpy(temp, map + (i - startblock), sizeof(temp));
+			for (j = 0 ; j < 4 ; j++)
+				temp[j] = le32_to_cpu(temp[j]);
+			rt2800_efuse_write_phys(rt2x00dev, (u16 *)temp, i>>1);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(rt2800_write_eeprom_efuse);
+
 static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 {
 	struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a128cea..c266c79 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -207,7 +207,10 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+			      const u16 length);
+void rt2800_write_eeprom_efuse(struct rt2x00_dev *rt2x00dev, u16 *eeprom,
+			       const u16 length);
 
 int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
 
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 9224d87..7782002 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -173,7 +173,7 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
 
 static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
-	rt2800_read_eeprom_efuse(rt2x00dev);
+	rt2800_read_eeprom_efuse(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
 }
 #else
 static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 85a4b62..069be20 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -733,12 +733,42 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
 }
 
 /*
+ *  EEPROM manipulation functions,
+ */
+static int rt2800usb_load_eeprom(struct rt2x00_dev *rt2x00dev,
+				 u16 *eeprom, const u16 length)
+{
+	u16 len = min_t(u16, length, EEPROM_SIZE);
+
+	if (rt2800_efuse_detect(rt2x00dev))
+		rt2800_read_eeprom_efuse(rt2x00dev, eeprom, len);
+	else
+		rt2x00usb_eeprom_read(rt2x00dev, eeprom, len);
+
+	return len;
+}
+
+static int rt2800usb_store_eeprom(struct rt2x00_dev *rt2x00dev,
+				  u16 *eeprom, const u16 length)
+{
+	u16 len = min_t(u16, length, EEPROM_SIZE);
+
+	if (rt2800_efuse_detect(rt2x00dev))
+		rt2800_write_eeprom_efuse(rt2x00dev, eeprom, len);
+	else
+		rt2x00usb_eeprom_write(rt2x00dev, eeprom, len);
+
+	return length;
+}
+
+/*
  * Device probe functions.
  */
 static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
 	if (rt2800_efuse_detect(rt2x00dev))
-		rt2800_read_eeprom_efuse(rt2x00dev);
+		rt2800_read_eeprom_efuse(rt2x00dev, rt2x00dev->eeprom,
+					 EEPROM_SIZE);
 	else
 		rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
 				      EEPROM_SIZE);
@@ -844,6 +874,9 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
 	.config			= rt2800_config,
 	.sta_add		= rt2800_sta_add,
 	.sta_remove		= rt2800_sta_remove,
+
+	.eeprom_load            = rt2800usb_load_eeprom,
+	.eeprom_store           = rt2800usb_store_eeprom,
 };
 
 static const struct data_queue_desc rt2800usb_queue_rx = {
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35..8fd81f5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -648,6 +648,12 @@ struct rt2x00lib_ops {
 			struct ieee80211_sta *sta);
 	int (*sta_remove) (struct rt2x00_dev *rt2x00dev,
 			   int wcid);
+
+	/* EEPROM manipulation */
+	int (*eeprom_load) (struct rt2x00_dev *rt2x00dev,
+			    u16 *eeprom, const u16 max_length);
+	int (*eeprom_store) (struct rt2x00_dev *rt2x00dev,
+			     u16 *eeprom, const u16 max_length);
 };
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 3bb8caf..1b8de4b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -86,6 +86,7 @@ struct rt2x00debug_intf {
 	struct dentry *csr_val_entry;
 	struct dentry *eeprom_off_entry;
 	struct dentry *eeprom_val_entry;
+	struct dentry *eeprom_commit_entry;
 	struct dentry *bbp_off_entry;
 	struct dentry *bbp_val_entry;
 	struct dentry *rf_off_entry;
@@ -650,6 +651,44 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
 	return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
 }
 
+static ssize_t rt2x00debug_eeprom_commit_write(struct file *file,
+					       const char __user *buf,
+					       size_t length,
+					       loff_t *offset)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+
+	if (intf->rt2x00dev->ops->lib->eeprom_store)
+		intf->rt2x00dev->ops->lib->eeprom_store(intf->rt2x00dev,
+							intf->rt2x00dev->eeprom,
+							intf->rt2x00dev->ops->eeprom_size);
+
+	return length;
+}
+static ssize_t rt2x00debug_eeprom_commit_read(struct file *file,
+					      char __user *buf,
+					      size_t length,
+					      loff_t *offset)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+
+	if (intf->rt2x00dev->ops->lib->eeprom_load)
+		intf->rt2x00dev->ops->lib->eeprom_load(intf->rt2x00dev,
+						       intf->rt2x00dev->eeprom,
+						       intf->rt2x00dev->ops->eeprom_size);
+
+	return 0;
+}
+
+static const struct file_operations rt2x00debug_fop_eeprom_commit = {
+	.owner		= THIS_MODULE,
+	.write		= rt2x00debug_eeprom_commit_write,
+	.read		= rt2x00debug_eeprom_commit_read,
+	.open		= rt2x00debug_file_open,
+	.release	= rt2x00debug_file_release,
+	.llseek		= default_llseek,
+};
+
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 {
 	const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
@@ -730,6 +769,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 
 #undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
 
+	intf->eeprom_commit_entry =
+		debugfs_create_file("eeprom_commit", S_IRUSR | S_IWUSR,
+				    intf->register_folder,
+				    intf, &rt2x00debug_fop_eeprom_commit);
+	if (IS_ERR(intf->eeprom_commit_entry) || !intf->eeprom_commit_entry)
+		goto exit;
+
 	intf->queue_folder =
 	    debugfs_create_dir("queue", intf->driver_folder);
 	if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
@@ -786,6 +832,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
 	debugfs_remove(intf->bbp_off_entry);
 	debugfs_remove(intf->eeprom_val_entry);
 	debugfs_remove(intf->eeprom_off_entry);
+	debugfs_remove(intf->eeprom_commit_entry);
 	debugfs_remove(intf->csr_val_entry);
 	debugfs_remove(intf->csr_off_entry);
 	debugfs_remove(intf->register_folder);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 323ca7b..f8ed3de 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -203,6 +203,25 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
 }
 
 /**
+ * rt2x00usb_eeprom_write - Write eeprom to device
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @eeprom: Pointer to eeprom array to copy the information from
+ * @length: Number of bytes to write to the eeprom
+ *
+ * Simple wrapper around rt2x00usb_vendor_request to write the eeprom
+ * to the device. Note that the eeprom argument _must_ be allocated using
+ * kmalloc for correct handling inside the kernel USB layer.
+ */
+static inline int rt2x00usb_eeprom_write(struct rt2x00_dev *rt2x00dev,
+					 __le16 *eeprom, const u16 length)
+{
+	return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_WRITE,
+					USB_VENDOR_REQUEST_OUT, 0, 0,
+					eeprom, length,
+					REGISTER_TIMEOUT16(length));
+}
+
+/**
  * rt2x00usb_register_read - Read 32bit register word
  * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
  * @offset: Register offset
