-+
-+/*
-+ * writes the appropriate range of flash, a NULL buf simply erases
-+ * the region of flash
-+ */
-+int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_sflash *sfl;
-+ u8 *block = NULL, *cur_ptr, *blk_ptr;
-+ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
-+ u32 blk_offset, blk_len, copied;
-+ int bytes, ret = 0;
-+
-+ /* Check address range */
-+ if (len <= 0)
-+ return 0;
-+
-+ sfl = &cc->sflash;
-+ if ((offset + len) > sfl->size)
-+ return -EINVAL;
-+
-+ blocksize = sfl->blocksize;
-+ mask = blocksize - 1;
-+
-+ /* Allocate a block of mem */
-+ block = kmalloc(blocksize, GFP_KERNEL);
-+ if (!block)
-+ return -ENOMEM;
-+
-+ while (len) {
-+ /* Align offset */
-+ cur_offset = offset & ~mask;
-+ cur_length = blocksize;
-+ cur_ptr = block;
-+
-+ remainder = blocksize - (offset & mask);
-+ if (len < remainder)
-+ cur_retlen = len;
-+ else
-+ cur_retlen = remainder;
-+
-+ /* buf == NULL means erase only */
-+ if (buf) {
-+ /* Copy existing data into holding block if necessary */
-+ if ((offset & mask) || (len < blocksize)) {
-+ blk_offset = cur_offset;
-+ blk_len = cur_length;
-+ blk_ptr = cur_ptr;
-+
-+ /* Copy entire block */
-+ while (blk_len) {
-+ copied = bcma_sflash_read(cc,
-+ blk_offset,
-+ blk_len, blk_ptr);
-+ blk_offset += copied;
-+ blk_len -= copied;
-+ blk_ptr += copied;
-+ }
-+ }
-+
-+ /* Copy input data into holding block */
-+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
-+ }
-+
-+ /* Erase block */
-+ ret = bcma_sflash_erase(cc, cur_offset);
-+ if (ret < 0)
-+ goto done;
-+
-+ while (bcma_sflash_poll(cc, cur_offset));
-+
-+ /* buf == NULL means erase only */
-+ if (!buf) {
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ continue;
-+ }
-+
-+ /* Write holding block */
-+ while (cur_length > 0) {
-+ bytes = bcma_sflash_write(cc, cur_offset,
-+ cur_length, cur_ptr);
-+
-+ if (bytes < 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+
-+ while (bcma_sflash_poll(cc, cur_offset))
-+ ;
-+
-+ cur_offset += bytes;
-+ cur_length -= bytes;
-+ cur_ptr += bytes;
-+ }
-+
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ buf += cur_retlen;
-+ }
-+
-+ ret = len;
-+done:
-+ kfree(block);
-+ return ret;
-+}