staging/rdma/hfi1: Adjust EPROM partitions, add EPROM commands

Add a new EPROM partition, adjusting partition placement.

Add EPROM range commands as a supserset of the partition
commands.  Remove old partition commands.

Enhance EPROM erase, creating a range function and using the
largest erase (sub) commands when possible.

Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Dean Luick <dean.luick@intel.com>
Signed-off-by: Jubin John <jubin.john@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Dean Luick 2015-11-16 21:59:35 -05:00 committed by Greg Kroah-Hartman
parent 5d9157aafb
commit cd371e0959
3 changed files with 77 additions and 70 deletions

View File

@ -53,17 +53,26 @@
#include "eprom.h"
/*
* The EPROM is logically divided into two partitions:
* The EPROM is logically divided into three partitions:
* partition 0: the first 128K, visible from PCI ROM BAR
* partition 1: the rest
* partition 1: 4K config file (sector size)
* partition 2: the rest
*/
#define P0_SIZE (128 * 1024)
#define P1_SIZE (4 * 1024)
#define P1_START P0_SIZE
#define P2_START (P0_SIZE + P1_SIZE)
/* erase sizes supported by the controller */
#define SIZE_4KB (4 * 1024)
#define MASK_4KB (SIZE_4KB - 1)
/* largest erase size supported by the controller */
#define SIZE_32KB (32 * 1024)
#define MASK_32KB (SIZE_32KB - 1)
#define SIZE_64KB (64 * 1024)
#define MASK_64KB (SIZE_64KB - 1)
/* controller page size, in bytes */
#define EP_PAGE_SIZE 256
#define EEP_PAGE_MASK (EP_PAGE_SIZE - 1)
@ -75,10 +84,12 @@
#define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr)
#define CMD_READ_SR1 ((0x05 << CMD_SHIFT))
#define CMD_WRITE_ENABLE ((0x06 << CMD_SHIFT))
#define CMD_SECTOR_ERASE_4KB(addr) ((0x20 << CMD_SHIFT) | addr)
#define CMD_SECTOR_ERASE_32KB(addr) ((0x52 << CMD_SHIFT) | addr)
#define CMD_CHIP_ERASE ((0x60 << CMD_SHIFT))
#define CMD_READ_MANUF_DEV_ID ((0x90 << CMD_SHIFT))
#define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT))
#define CMD_SECTOR_ERASE_64KB(addr) ((0xd8 << CMD_SHIFT) | addr)
/* controller interface speeds */
#define EP_SPEED_FULL 0x2 /* full speed */
@ -188,28 +199,43 @@ static int erase_chip(struct hfi1_devdata *dd)
}
/*
* Erase a range using the 32KB erase command.
* Erase a range.
*/
static int erase_32kb_range(struct hfi1_devdata *dd, u32 start, u32 end)
static int erase_range(struct hfi1_devdata *dd, u32 start, u32 len)
{
u32 end = start + len;
int ret = 0;
if (end < start)
return -EINVAL;
if ((start & MASK_32KB) || (end & MASK_32KB)) {
/* check the end points for the minimum erase */
if ((start & MASK_4KB) || (end & MASK_4KB)) {
dd_dev_err(dd,
"%s: non-aligned range (0x%x,0x%x) for a 32KB erase\n",
"%s: non-aligned range (0x%x,0x%x) for a 4KB erase\n",
__func__, start, end);
return -EINVAL;
}
write_enable(dd);
for (; start < end; start += SIZE_32KB) {
while (start < end) {
write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_WRITE_ENABLE);
write_csr(dd, ASIC_EEP_ADDR_CMD,
CMD_SECTOR_ERASE_32KB(start));
/* check in order of largest to smallest */
if (((start & MASK_64KB) == 0) && (start + SIZE_64KB <= end)) {
write_csr(dd, ASIC_EEP_ADDR_CMD,
CMD_SECTOR_ERASE_64KB(start));
start += SIZE_64KB;
} else if (((start & MASK_32KB) == 0) &&
(start + SIZE_32KB <= end)) {
write_csr(dd, ASIC_EEP_ADDR_CMD,
CMD_SECTOR_ERASE_32KB(start));
start += SIZE_32KB;
} else { /* 4KB will work */
write_csr(dd, ASIC_EEP_ADDR_CMD,
CMD_SECTOR_ERASE_4KB(start));
start += SIZE_4KB;
}
ret = wait_for_not_busy(dd);
if (ret)
goto done;
@ -309,6 +335,18 @@ static int write_length(struct hfi1_devdata *dd, u32 start, u32 len, u64 addr)
return ret;
}
/* convert an range composite to a length, in bytes */
static inline u32 extract_rlen(u32 composite)
{
return (composite & 0xffff) * EP_PAGE_SIZE;
}
/* convert an range composite to a start, in bytes */
static inline u32 extract_rstart(u32 composite)
{
return (composite >> 16) * EP_PAGE_SIZE;
}
/*
* Perform the given operation on the EPROM. Called from user space. The
* user credentials have already been checked.
@ -319,6 +357,8 @@ int handle_eprom_command(const struct hfi1_cmd *cmd)
{
struct hfi1_devdata *dd;
u32 dev_id;
u32 rlen; /* range length */
u32 rstart; /* range start */
int ret = 0;
/*
@ -364,54 +404,29 @@ int handle_eprom_command(const struct hfi1_cmd *cmd)
sizeof(u32)))
ret = -EFAULT;
break;
case HFI1_CMD_EP_ERASE_CHIP:
ret = erase_chip(dd);
break;
case HFI1_CMD_EP_ERASE_P0:
if (cmd->len != P0_SIZE) {
ret = -ERANGE;
break;
}
ret = erase_32kb_range(dd, 0, cmd->len);
case HFI1_CMD_EP_ERASE_RANGE:
rlen = extract_rlen(cmd->len);
rstart = extract_rstart(cmd->len);
ret = erase_range(dd, rstart, rlen);
break;
case HFI1_CMD_EP_ERASE_P1:
/* check for overflow */
if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
ret = -ERANGE;
break;
}
ret = erase_32kb_range(dd, P1_START, P1_START + cmd->len);
case HFI1_CMD_EP_READ_RANGE:
rlen = extract_rlen(cmd->len);
rstart = extract_rstart(cmd->len);
ret = read_length(dd, rstart, rlen, cmd->addr);
break;
case HFI1_CMD_EP_READ_P0:
if (cmd->len != P0_SIZE) {
ret = -ERANGE;
break;
}
ret = read_length(dd, 0, cmd->len, cmd->addr);
break;
case HFI1_CMD_EP_READ_P1:
/* check for overflow */
if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
ret = -ERANGE;
break;
}
ret = read_length(dd, P1_START, cmd->len, cmd->addr);
break;
case HFI1_CMD_EP_WRITE_P0:
if (cmd->len > P0_SIZE) {
ret = -ERANGE;
break;
}
ret = write_length(dd, 0, cmd->len, cmd->addr);
break;
case HFI1_CMD_EP_WRITE_P1:
/* check for overflow */
if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
ret = -ERANGE;
break;
}
ret = write_length(dd, P1_START, cmd->len, cmd->addr);
case HFI1_CMD_EP_WRITE_RANGE:
rlen = extract_rlen(cmd->len);
rstart = extract_rstart(cmd->len);
ret = write_length(dd, rstart, rlen, cmd->addr);
break;
default:
dd_dev_err(dd, "%s: unexpected command %d\n",
__func__, cmd->type);

View File

@ -234,12 +234,9 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
break;
case HFI1_CMD_EP_INFO:
case HFI1_CMD_EP_ERASE_CHIP:
case HFI1_CMD_EP_ERASE_P0:
case HFI1_CMD_EP_ERASE_P1:
case HFI1_CMD_EP_READ_P0:
case HFI1_CMD_EP_READ_P1:
case HFI1_CMD_EP_WRITE_P0:
case HFI1_CMD_EP_WRITE_P1:
case HFI1_CMD_EP_ERASE_RANGE:
case HFI1_CMD_EP_READ_RANGE:
case HFI1_CMD_EP_WRITE_RANGE:
uctxt_required = 0; /* assigned user context not required */
must_be_root = 1; /* validate user */
copy = 0;
@ -393,12 +390,9 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
}
case HFI1_CMD_EP_INFO:
case HFI1_CMD_EP_ERASE_CHIP:
case HFI1_CMD_EP_ERASE_P0:
case HFI1_CMD_EP_ERASE_P1:
case HFI1_CMD_EP_READ_P0:
case HFI1_CMD_EP_READ_P1:
case HFI1_CMD_EP_WRITE_P0:
case HFI1_CMD_EP_WRITE_P1:
case HFI1_CMD_EP_ERASE_RANGE:
case HFI1_CMD_EP_READ_RANGE:
case HFI1_CMD_EP_WRITE_RANGE:
ret = handle_eprom_command(&cmd);
break;
}

View File

@ -137,12 +137,10 @@
/* separate EPROM commands from normal PSM commands */
#define HFI1_CMD_EP_INFO 64 /* read EPROM device ID */
#define HFI1_CMD_EP_ERASE_CHIP 65 /* erase whole EPROM */
#define HFI1_CMD_EP_ERASE_P0 66 /* erase EPROM partition 0 */
#define HFI1_CMD_EP_ERASE_P1 67 /* erase EPROM partition 1 */
#define HFI1_CMD_EP_READ_P0 68 /* read EPROM partition 0 */
#define HFI1_CMD_EP_READ_P1 69 /* read EPROM partition 1 */
#define HFI1_CMD_EP_WRITE_P0 70 /* write EPROM partition 0 */
#define HFI1_CMD_EP_WRITE_P1 71 /* write EPROM partition 1 */
/* range 66-74 no longer used */
#define HFI1_CMD_EP_ERASE_RANGE 75 /* erase EPROM range */
#define HFI1_CMD_EP_READ_RANGE 76 /* read EPROM range */
#define HFI1_CMD_EP_WRITE_RANGE 77 /* write EPROM range */
#define _HFI1_EVENT_FROZEN_BIT 0
#define _HFI1_EVENT_LINKDOWN_BIT 1