mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
isci: remove 'min memory' infrastructure
The old 'core' had aspirations of running in severely memory constrained environments like bios option-rom, it's not needed for Linux and gets in the way of other cleanups (like unifying/reducing the number of structure members in scic_sds_controller/isci_host). This also fixes a theoretical bug in that the driver would blindly override the silicon advertised limits for number of ports, task contexts, and remote node contexts. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
dbb0743a58
commit
7c78da3175
@ -70,46 +70,24 @@
|
||||
|
||||
#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200
|
||||
|
||||
/**
|
||||
* smu_dcc_get_max_ports() -
|
||||
*
|
||||
* This macro returns the maximum number of logical ports supported by the
|
||||
* hardware. The caller passes in the value read from the device context
|
||||
* capacity register and this macro will mash and shift the value appropriately.
|
||||
*/
|
||||
#define smu_dcc_get_max_ports(dcc_value) \
|
||||
#define smu_max_ports(dcc_value) \
|
||||
(\
|
||||
(((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \
|
||||
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT) + 1 \
|
||||
)
|
||||
|
||||
/**
|
||||
* smu_dcc_get_max_task_context() -
|
||||
*
|
||||
* This macro returns the maximum number of task contexts supported by the
|
||||
* hardware. The caller passes in the value read from the device context
|
||||
* capacity register and this macro will mash and shift the value appropriately.
|
||||
*/
|
||||
#define smu_dcc_get_max_task_context(dcc_value) \
|
||||
#define smu_max_task_contexts(dcc_value) \
|
||||
(\
|
||||
(((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \
|
||||
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT) + 1 \
|
||||
)
|
||||
|
||||
/**
|
||||
* smu_dcc_get_max_remote_node_context() -
|
||||
*
|
||||
* This macro returns the maximum number of remote node contexts supported by
|
||||
* the hardware. The caller passes in the value read from the device context
|
||||
* capacity register and this macro will mash and shift the value appropriately.
|
||||
*/
|
||||
#define smu_dcc_get_max_remote_node_context(dcc_value) \
|
||||
#define smu_max_rncs(dcc_value) \
|
||||
(\
|
||||
(((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \
|
||||
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT) + 1 \
|
||||
)
|
||||
|
||||
|
||||
#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100
|
||||
|
||||
/**
|
||||
@ -153,9 +131,8 @@
|
||||
INCREMENT_QUEUE_GET(\
|
||||
(index), \
|
||||
(cycle), \
|
||||
(controller)->completion_queue_entries, \
|
||||
SMU_CQGR_CYCLE_BIT \
|
||||
)
|
||||
SCU_MAX_COMPLETION_QUEUE_ENTRIES, \
|
||||
SMU_CQGR_CYCLE_BIT)
|
||||
|
||||
/**
|
||||
* INCREMENT_EVENT_QUEUE_GET() -
|
||||
@ -167,7 +144,7 @@
|
||||
INCREMENT_QUEUE_GET(\
|
||||
(index), \
|
||||
(cycle), \
|
||||
(controller)->completion_event_entries, \
|
||||
SCU_MAX_EVENTS, \
|
||||
SMU_CQGR_EVENT_CYCLE_BIT \
|
||||
)
|
||||
|
||||
@ -843,10 +820,9 @@ static void scic_sds_controller_initialize_completion_queue(struct scic_sds_cont
|
||||
|
||||
scic->completion_queue_get = 0;
|
||||
|
||||
completion_queue_control_value = (
|
||||
SMU_CQC_QUEUE_LIMIT_SET(scic->completion_queue_entries - 1)
|
||||
| SMU_CQC_EVENT_LIMIT_SET(scic->completion_event_entries - 1)
|
||||
);
|
||||
completion_queue_control_value =
|
||||
(SMU_CQC_QUEUE_LIMIT_SET(SCU_MAX_COMPLETION_QUEUE_ENTRIES - 1) |
|
||||
SMU_CQC_EVENT_LIMIT_SET(SCU_MAX_EVENTS - 1));
|
||||
|
||||
writel(completion_queue_control_value,
|
||||
&scic->smu_registers->completion_queue_control);
|
||||
@ -873,7 +849,7 @@ static void scic_sds_controller_initialize_completion_queue(struct scic_sds_cont
|
||||
&scic->smu_registers->completion_queue_put);
|
||||
|
||||
/* Initialize the cycle bit of the completion queue entries */
|
||||
for (index = 0; index < scic->completion_queue_entries; index++) {
|
||||
for (index = 0; index < SCU_MAX_COMPLETION_QUEUE_ENTRIES; index++) {
|
||||
/*
|
||||
* If get.cycle_bit != completion_queue.cycle_bit
|
||||
* its not a valid completion queue entry
|
||||
@ -890,8 +866,7 @@ static void scic_sds_controller_initialize_unsolicited_frame_queue(struct scic_s
|
||||
|
||||
/* Write the queue size */
|
||||
frame_queue_control_value =
|
||||
SCU_UFQC_GEN_VAL(QUEUE_SIZE,
|
||||
scic->uf_control.address_table.count);
|
||||
SCU_UFQC_GEN_VAL(QUEUE_SIZE, SCU_MAX_UNSOLICITED_FRAMES);
|
||||
|
||||
writel(frame_queue_control_value,
|
||||
&scic->scu_registers->sdma.unsolicited_frame_queue_control);
|
||||
@ -1863,15 +1838,6 @@ static enum sci_status scic_controller_construct(struct scic_sds_controller *sci
|
||||
|
||||
sci_init_timer(&scic->timer, controller_timeout);
|
||||
|
||||
/* Set the default maximum values */
|
||||
scic->completion_event_entries = SCU_EVENT_COUNT;
|
||||
scic->completion_queue_entries = SCU_COMPLETION_QUEUE_COUNT;
|
||||
scic->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
|
||||
scic->logical_port_entries = SCI_MAX_PORTS;
|
||||
scic->task_context_entries = SCU_IO_REQUEST_COUNT;
|
||||
scic->uf_control.buffers.count = SCU_UNSOLICITED_FRAME_COUNT;
|
||||
scic->uf_control.address_table.count = SCU_UNSOLICITED_FRAME_COUNT;
|
||||
|
||||
/* Initialize the User and OEM parameters to default values. */
|
||||
scic_sds_controller_set_default_config_parameters(scic);
|
||||
|
||||
@ -2207,44 +2173,6 @@ static void scic_sds_controller_afe_initialization(struct scic_sds_controller *s
|
||||
udelay(AFE_REGISTER_WRITE_DELAY);
|
||||
}
|
||||
|
||||
static enum sci_status scic_controller_set_mode(struct scic_sds_controller *scic,
|
||||
enum sci_controller_mode operating_mode)
|
||||
{
|
||||
enum sci_status status = SCI_SUCCESS;
|
||||
|
||||
if ((scic->sm.current_state_id == SCIC_INITIALIZING) ||
|
||||
(scic->sm.current_state_id == SCIC_INITIALIZED)) {
|
||||
switch (operating_mode) {
|
||||
case SCI_MODE_SPEED:
|
||||
scic->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
|
||||
scic->task_context_entries = SCU_IO_REQUEST_COUNT;
|
||||
scic->uf_control.buffers.count =
|
||||
SCU_UNSOLICITED_FRAME_COUNT;
|
||||
scic->completion_event_entries = SCU_EVENT_COUNT;
|
||||
scic->completion_queue_entries =
|
||||
SCU_COMPLETION_QUEUE_COUNT;
|
||||
break;
|
||||
|
||||
case SCI_MODE_SIZE:
|
||||
scic->remote_node_entries = SCI_MIN_REMOTE_DEVICES;
|
||||
scic->task_context_entries = SCI_MIN_IO_REQUESTS;
|
||||
scic->uf_control.buffers.count =
|
||||
SCU_MIN_UNSOLICITED_FRAMES;
|
||||
scic->completion_event_entries = SCU_MIN_EVENTS;
|
||||
scic->completion_queue_entries =
|
||||
SCU_MIN_COMPLETION_QUEUE_ENTRIES;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
status = SCI_FAILURE_INVALID_STATE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void scic_sds_controller_initialize_power_control(struct scic_sds_controller *scic)
|
||||
{
|
||||
sci_init_timer(&scic->power_control.timer, power_control_timeout);
|
||||
@ -2259,9 +2187,9 @@ static void scic_sds_controller_initialize_power_control(struct scic_sds_control
|
||||
static enum sci_status scic_controller_initialize(struct scic_sds_controller *scic)
|
||||
{
|
||||
struct sci_base_state_machine *sm = &scic->sm;
|
||||
enum sci_status result = SCI_SUCCESS;
|
||||
struct isci_host *ihost = scic_to_ihost(scic);
|
||||
u32 index, state;
|
||||
enum sci_status result = SCI_FAILURE;
|
||||
unsigned long i, state, val;
|
||||
|
||||
if (scic->sm.current_state_id != SCIC_RESET) {
|
||||
dev_warn(scic_to_dev(scic),
|
||||
@ -2286,133 +2214,81 @@ static enum sci_status scic_controller_initialize(struct scic_sds_controller *sc
|
||||
* / presently they seem to be wrong. */
|
||||
scic_sds_controller_afe_initialization(scic);
|
||||
|
||||
if (result == SCI_SUCCESS) {
|
||||
|
||||
/* Take the hardware out of reset */
|
||||
writel(0, &scic->smu_registers->soft_reset_control);
|
||||
|
||||
/*
|
||||
* / @todo Provide meaningfull error code for hardware failure
|
||||
* result = SCI_FAILURE_CONTROLLER_HARDWARE; */
|
||||
for (i = 100; i >= 1; i--) {
|
||||
u32 status;
|
||||
u32 terminate_loop;
|
||||
|
||||
/* Take the hardware out of reset */
|
||||
writel(0, &scic->smu_registers->soft_reset_control);
|
||||
/* Loop until the hardware reports success */
|
||||
udelay(SCU_CONTEXT_RAM_INIT_STALL_TIME);
|
||||
status = readl(&scic->smu_registers->control_status);
|
||||
|
||||
/*
|
||||
* / @todo Provide meaningfull error code for hardware failure
|
||||
* result = SCI_FAILURE_CONTROLLER_HARDWARE; */
|
||||
result = SCI_FAILURE;
|
||||
terminate_loop = 100;
|
||||
|
||||
while (terminate_loop-- && (result != SCI_SUCCESS)) {
|
||||
/* Loop until the hardware reports success */
|
||||
udelay(SCU_CONTEXT_RAM_INIT_STALL_TIME);
|
||||
status = readl(&scic->smu_registers->control_status);
|
||||
|
||||
if ((status & SCU_RAM_INIT_COMPLETED) ==
|
||||
SCU_RAM_INIT_COMPLETED)
|
||||
result = SCI_SUCCESS;
|
||||
}
|
||||
if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED)
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
goto out;
|
||||
|
||||
if (result == SCI_SUCCESS) {
|
||||
u32 max_supported_ports;
|
||||
u32 max_supported_devices;
|
||||
u32 max_supported_io_requests;
|
||||
u32 device_context_capacity;
|
||||
/*
|
||||
* Determine what are the actaul device capacities that the
|
||||
* hardware will support */
|
||||
val = readl(&scic->smu_registers->device_context_capacity);
|
||||
|
||||
/*
|
||||
* Determine what are the actaul device capacities that the
|
||||
* hardware will support */
|
||||
device_context_capacity =
|
||||
readl(&scic->smu_registers->device_context_capacity);
|
||||
/* Record the smaller of the two capacity values */
|
||||
scic->logical_port_entries = min(smu_max_ports(val), SCI_MAX_PORTS);
|
||||
scic->task_context_entries = min(smu_max_task_contexts(val), SCI_MAX_IO_REQUESTS);
|
||||
scic->remote_node_entries = min(smu_max_rncs(val), SCI_MAX_REMOTE_DEVICES);
|
||||
|
||||
/*
|
||||
* Make all PEs that are unassigned match up with the
|
||||
* logical ports
|
||||
*/
|
||||
for (i = 0; i < scic->logical_port_entries; i++) {
|
||||
struct scu_port_task_scheduler_group_registers __iomem
|
||||
*ptsg = &scic->scu_registers->peg0.ptsg;
|
||||
|
||||
max_supported_ports = smu_dcc_get_max_ports(device_context_capacity);
|
||||
max_supported_devices = smu_dcc_get_max_remote_node_context(device_context_capacity);
|
||||
max_supported_io_requests = smu_dcc_get_max_task_context(device_context_capacity);
|
||||
|
||||
/*
|
||||
* Make all PEs that are unassigned match up with the
|
||||
* logical ports
|
||||
*/
|
||||
for (index = 0; index < max_supported_ports; index++) {
|
||||
struct scu_port_task_scheduler_group_registers __iomem
|
||||
*ptsg = &scic->scu_registers->peg0.ptsg;
|
||||
|
||||
writel(index, &ptsg->protocol_engine[index]);
|
||||
}
|
||||
|
||||
/* Record the smaller of the two capacity values */
|
||||
scic->logical_port_entries =
|
||||
min(max_supported_ports, scic->logical_port_entries);
|
||||
|
||||
scic->task_context_entries =
|
||||
min(max_supported_io_requests,
|
||||
scic->task_context_entries);
|
||||
|
||||
scic->remote_node_entries =
|
||||
min(max_supported_devices, scic->remote_node_entries);
|
||||
|
||||
/*
|
||||
* Now that we have the correct hardware reported minimum values
|
||||
* build the MDL for the controller. Default to a performance
|
||||
* configuration.
|
||||
*/
|
||||
scic_controller_set_mode(scic, SCI_MODE_SPEED);
|
||||
writel(i, &ptsg->protocol_engine[i]);
|
||||
}
|
||||
|
||||
/* Initialize hardware PCI Relaxed ordering in DMA engines */
|
||||
if (result == SCI_SUCCESS) {
|
||||
u32 dma_configuration;
|
||||
val = readl(&scic->scu_registers->sdma.pdma_configuration);
|
||||
val |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
|
||||
writel(val, &scic->scu_registers->sdma.pdma_configuration);
|
||||
|
||||
/* Configure the payload DMA */
|
||||
dma_configuration =
|
||||
readl(&scic->scu_registers->sdma.pdma_configuration);
|
||||
dma_configuration |=
|
||||
SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
|
||||
writel(dma_configuration,
|
||||
&scic->scu_registers->sdma.pdma_configuration);
|
||||
|
||||
/* Configure the control DMA */
|
||||
dma_configuration =
|
||||
readl(&scic->scu_registers->sdma.cdma_configuration);
|
||||
dma_configuration |=
|
||||
SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
|
||||
writel(dma_configuration,
|
||||
&scic->scu_registers->sdma.cdma_configuration);
|
||||
}
|
||||
val = readl(&scic->scu_registers->sdma.cdma_configuration);
|
||||
val |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
|
||||
writel(val, &scic->scu_registers->sdma.cdma_configuration);
|
||||
|
||||
/*
|
||||
* Initialize the PHYs before the PORTs because the PHY registers
|
||||
* are accessed during the port initialization.
|
||||
*/
|
||||
if (result == SCI_SUCCESS) {
|
||||
/* Initialize the phys */
|
||||
for (index = 0;
|
||||
(result == SCI_SUCCESS) && (index < SCI_MAX_PHYS);
|
||||
index++) {
|
||||
result = scic_sds_phy_initialize(
|
||||
&ihost->phys[index].sci,
|
||||
&scic->scu_registers->peg0.pe[index].tl,
|
||||
&scic->scu_registers->peg0.pe[index].ll);
|
||||
}
|
||||
for (i = 0; i < SCI_MAX_PHYS; i++) {
|
||||
result = scic_sds_phy_initialize(&ihost->phys[i].sci,
|
||||
&scic->scu_registers->peg0.pe[i].tl,
|
||||
&scic->scu_registers->peg0.pe[i].ll);
|
||||
if (result != SCI_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result == SCI_SUCCESS) {
|
||||
/* Initialize the logical ports */
|
||||
for (index = 0;
|
||||
(index < scic->logical_port_entries) &&
|
||||
(result == SCI_SUCCESS);
|
||||
index++) {
|
||||
result = scic_sds_port_initialize(
|
||||
&ihost->ports[index].sci,
|
||||
&scic->scu_registers->peg0.ptsg.port[index],
|
||||
&scic->scu_registers->peg0.ptsg.protocol_engine,
|
||||
&scic->scu_registers->peg0.viit[index]);
|
||||
}
|
||||
for (i = 0; i < scic->logical_port_entries; i++) {
|
||||
result = scic_sds_port_initialize(&ihost->ports[i].sci,
|
||||
&scic->scu_registers->peg0.ptsg.port[i],
|
||||
&scic->scu_registers->peg0.ptsg.protocol_engine,
|
||||
&scic->scu_registers->peg0.viit[i]);
|
||||
|
||||
if (result != SCI_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result == SCI_SUCCESS)
|
||||
result = scic_sds_port_configuration_agent_initialize(
|
||||
scic,
|
||||
&scic->port_agent);
|
||||
result = scic_sds_port_configuration_agent_initialize(scic, &scic->port_agent);
|
||||
|
||||
out:
|
||||
/* Advance the controller state machine */
|
||||
if (result == SCI_SUCCESS)
|
||||
state = SCIC_INITIALIZED;
|
||||
@ -2480,47 +2356,38 @@ static enum sci_status scic_user_parameters_set(
|
||||
static int scic_controller_mem_init(struct scic_sds_controller *scic)
|
||||
{
|
||||
struct device *dev = scic_to_dev(scic);
|
||||
dma_addr_t dma_handle;
|
||||
enum sci_status result;
|
||||
dma_addr_t dma;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
scic->completion_queue = dmam_alloc_coherent(dev,
|
||||
scic->completion_queue_entries * sizeof(u32),
|
||||
&dma_handle, GFP_KERNEL);
|
||||
size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32);
|
||||
scic->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
|
||||
if (!scic->completion_queue)
|
||||
return -ENOMEM;
|
||||
|
||||
writel(lower_32_bits(dma_handle),
|
||||
&scic->smu_registers->completion_queue_lower);
|
||||
writel(upper_32_bits(dma_handle),
|
||||
&scic->smu_registers->completion_queue_upper);
|
||||
writel(lower_32_bits(dma), &scic->smu_registers->completion_queue_lower);
|
||||
writel(upper_32_bits(dma), &scic->smu_registers->completion_queue_upper);
|
||||
|
||||
scic->remote_node_context_table = dmam_alloc_coherent(dev,
|
||||
scic->remote_node_entries *
|
||||
sizeof(union scu_remote_node_context),
|
||||
&dma_handle, GFP_KERNEL);
|
||||
size = scic->remote_node_entries * sizeof(union scu_remote_node_context);
|
||||
scic->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma,
|
||||
GFP_KERNEL);
|
||||
if (!scic->remote_node_context_table)
|
||||
return -ENOMEM;
|
||||
|
||||
writel(lower_32_bits(dma_handle),
|
||||
&scic->smu_registers->remote_node_context_lower);
|
||||
writel(upper_32_bits(dma_handle),
|
||||
&scic->smu_registers->remote_node_context_upper);
|
||||
writel(lower_32_bits(dma), &scic->smu_registers->remote_node_context_lower);
|
||||
writel(upper_32_bits(dma), &scic->smu_registers->remote_node_context_upper);
|
||||
|
||||
scic->task_context_table = dmam_alloc_coherent(dev,
|
||||
scic->task_context_entries *
|
||||
sizeof(struct scu_task_context),
|
||||
&dma_handle, GFP_KERNEL);
|
||||
size = scic->task_context_entries * sizeof(struct scu_task_context),
|
||||
scic->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
|
||||
if (!scic->task_context_table)
|
||||
return -ENOMEM;
|
||||
|
||||
writel(lower_32_bits(dma_handle),
|
||||
&scic->smu_registers->host_task_table_lower);
|
||||
writel(upper_32_bits(dma_handle),
|
||||
&scic->smu_registers->host_task_table_upper);
|
||||
writel(lower_32_bits(dma), &scic->smu_registers->host_task_table_lower);
|
||||
writel(upper_32_bits(dma), &scic->smu_registers->host_task_table_upper);
|
||||
|
||||
result = scic_sds_unsolicited_frame_control_construct(scic);
|
||||
if (result)
|
||||
return result;
|
||||
err = scic_sds_unsolicited_frame_control_construct(scic);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Inform the silicon as to the location of the UF headers and
|
||||
|
@ -239,18 +239,6 @@ struct scic_sds_controller {
|
||||
*/
|
||||
u32 logical_port_entries;
|
||||
|
||||
/**
|
||||
* This field is the minimum number of hardware supported completion queue
|
||||
* entries and the software requested completion queue entries.
|
||||
*/
|
||||
u32 completion_queue_entries;
|
||||
|
||||
/**
|
||||
* This field is the minimum number of hardware supported event entries and
|
||||
* the software requested event entries.
|
||||
*/
|
||||
u32 completion_event_entries;
|
||||
|
||||
/**
|
||||
* This field is the minimum number of devices supported by the hardware and
|
||||
* the number of devices requested by the software.
|
||||
@ -325,7 +313,6 @@ struct isci_host {
|
||||
union scic_oem_parameters oem_parameters;
|
||||
|
||||
int id; /* unique within a given pci device */
|
||||
void *core_ctrl_memory;
|
||||
struct dma_pool *dma_pool;
|
||||
struct isci_phy phys[SCI_MAX_PHYS];
|
||||
struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
|
||||
|
@ -78,39 +78,16 @@ enum sci_controller_mode {
|
||||
SCI_MODE_SIZE /* deprecated */
|
||||
};
|
||||
|
||||
#define SCI_MAX_PHYS (4)
|
||||
#define SCI_MAX_PHYS (4UL)
|
||||
#define SCI_MAX_PORTS SCI_MAX_PHYS
|
||||
#define SCI_MIN_SMP_PHYS (38)
|
||||
#define SCI_MAX_SMP_PHYS (384) /* not silicon constrained */
|
||||
#define SCI_MAX_REMOTE_DEVICES (256)
|
||||
#define SCI_MIN_REMOTE_DEVICES (16)
|
||||
#define SCI_MAX_IO_REQUESTS (256)
|
||||
#define SCI_MIN_IO_REQUESTS (1)
|
||||
#define SCI_MAX_REMOTE_DEVICES (256UL)
|
||||
#define SCI_MAX_IO_REQUESTS (256UL)
|
||||
#define SCI_MAX_MSIX_MESSAGES (2)
|
||||
#define SCI_MAX_SCATTER_GATHER_ELEMENTS 130 /* not silicon constrained */
|
||||
#define SCI_MIN_SCATTER_GATHER_ELEMENTS 1
|
||||
#define SCI_MAX_CONTROLLERS 2
|
||||
#define SCI_MAX_DOMAINS SCI_MAX_PORTS
|
||||
|
||||
/* 2 indicates the maximum number of UFs that can occur for a given IO request.
|
||||
* The hardware handles reception of additional unsolicited frames while all
|
||||
* UFs are in use, by holding off the transmitting device. This number could
|
||||
* be theoretically reduced to 1, but 2 provides for more reliable operation.
|
||||
* During SATA PIO operation, it is possible under some conditions for there to
|
||||
* be 3 separate FISes received, back to back to back (PIO Setup, Data, D2H
|
||||
* Register). It is unlikely to have all 3 pending all at once without some of
|
||||
* them already being processed.
|
||||
*/
|
||||
#define SCU_MIN_UNSOLICITED_FRAMES (1)
|
||||
#define SCU_MIN_CRITICAL_NOTIFICATIONS (24)
|
||||
#define SCU_MIN_EVENTS (4)
|
||||
#define SCU_MIN_COMPLETION_QUEUE_SCRATCH (2)
|
||||
#define SCU_MIN_COMPLETION_QUEUE_ENTRIES (SCU_MIN_CRITICAL_NOTIFICATIONS \
|
||||
+ SCU_MIN_EVENTS \
|
||||
+ SCU_MIN_UNSOLICITED_FRAMES \
|
||||
+ SCI_MIN_IO_REQUESTS \
|
||||
+ SCU_MIN_COMPLETION_QUEUE_SCRATCH)
|
||||
|
||||
#define SCU_MAX_CRITICAL_NOTIFICATIONS (384)
|
||||
#define SCU_MAX_EVENTS (128)
|
||||
#define SCU_MAX_UNSOLICITED_FRAMES (128)
|
||||
@ -121,51 +98,6 @@ enum sci_controller_mode {
|
||||
+ SCI_MAX_IO_REQUESTS \
|
||||
+ SCU_MAX_COMPLETION_QUEUE_SCRATCH)
|
||||
|
||||
#if !defined(ENABLE_MINIMUM_MEMORY_MODE)
|
||||
#define SCU_UNSOLICITED_FRAME_COUNT SCU_MAX_UNSOLICITED_FRAMES
|
||||
#define SCU_CRITICAL_NOTIFICATION_COUNT SCU_MAX_CRITICAL_NOTIFICATIONS
|
||||
#define SCU_EVENT_COUNT SCU_MAX_EVENTS
|
||||
#define SCU_COMPLETION_QUEUE_SCRATCH SCU_MAX_COMPLETION_QUEUE_SCRATCH
|
||||
#define SCU_IO_REQUEST_COUNT SCI_MAX_IO_REQUESTS
|
||||
#define SCU_IO_REQUEST_SGE_COUNT SCI_MAX_SCATTER_GATHER_ELEMENTS
|
||||
#define SCU_COMPLETION_QUEUE_COUNT SCU_MAX_COMPLETION_QUEUE_ENTRIES
|
||||
#else
|
||||
#define SCU_UNSOLICITED_FRAME_COUNT SCU_MIN_UNSOLICITED_FRAMES
|
||||
#define SCU_CRITICAL_NOTIFICATION_COUNT SCU_MIN_CRITICAL_NOTIFICATIONS
|
||||
#define SCU_EVENT_COUNT SCU_MIN_EVENTS
|
||||
#define SCU_COMPLETION_QUEUE_SCRATCH SCU_MIN_COMPLETION_QUEUE_SCRATCH
|
||||
#define SCU_IO_REQUEST_COUNT SCI_MIN_IO_REQUESTS
|
||||
#define SCU_IO_REQUEST_SGE_COUNT SCI_MIN_SCATTER_GATHER_ELEMENTS
|
||||
#define SCU_COMPLETION_QUEUE_COUNT SCU_MIN_COMPLETION_QUEUE_ENTRIES
|
||||
#endif /* !defined(ENABLE_MINIMUM_MEMORY_OPERATION) */
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The SCU_COMPLETION_QUEUE_COUNT constant indicates the size of the completion
|
||||
* queue into which the hardware DMAs 32-bit quantas (completion entries).
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This queue must be programmed to a power of 2 size (e.g. 32, 64, 1024, etc.).
|
||||
*/
|
||||
#if (SCU_COMPLETION_QUEUE_COUNT != 16) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 32) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 64) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 128) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 256) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 512) && \
|
||||
(SCU_COMPLETION_QUEUE_COUNT != 1024)
|
||||
#error "SCU_COMPLETION_QUEUE_COUNT must be set to a power of 2."
|
||||
#endif
|
||||
|
||||
#if SCU_MIN_UNSOLICITED_FRAMES > SCU_MAX_UNSOLICITED_FRAMES
|
||||
#error "Invalid configuration of unsolicited frame constants"
|
||||
#endif /* SCU_MIN_UNSOLICITED_FRAMES > SCU_MAX_UNSOLICITED_FRAMES */
|
||||
|
||||
#define SCU_MIN_UF_TABLE_ENTRIES (8)
|
||||
#define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096)
|
||||
#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024)
|
||||
#define SCU_INVALID_FRAME_INDEX (0xFFFF)
|
||||
@ -173,14 +105,14 @@ enum sci_controller_mode {
|
||||
#define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF)
|
||||
#define SCU_IO_REQUEST_MAX_TRANSFER_LENGTH (0x00FFFFFF)
|
||||
|
||||
/*
|
||||
* Determine the size of the unsolicited frame array including
|
||||
* unused buffers. */
|
||||
#if SCU_UNSOLICITED_FRAME_COUNT <= SCU_MIN_UF_TABLE_ENTRIES
|
||||
#define SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE SCU_MIN_UF_TABLE_ENTRIES
|
||||
#else
|
||||
#define SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE SCU_MAX_UNSOLICITED_FRAMES
|
||||
#endif /* SCU_UNSOLICITED_FRAME_COUNT <= SCU_MIN_UF_TABLE_ENTRIES */
|
||||
static inline void check_sizes(void)
|
||||
{
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_EVENTS);
|
||||
BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES <= 8);
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES);
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES);
|
||||
BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum sci_status - This is the general return status enumeration for non-IO,
|
||||
|
@ -213,7 +213,7 @@ struct scic_sds_request {
|
||||
struct scu_task_context tc ____cacheline_aligned;
|
||||
|
||||
/* could be larger with sg chaining */
|
||||
#define SCU_SGL_SIZE ((SCU_IO_REQUEST_SGE_COUNT + 1) / 2)
|
||||
#define SCU_SGL_SIZE ((SCI_MAX_SCATTER_GATHER_ELEMENTS + 1) / 2)
|
||||
struct scu_sgl_element_pair sg_table[SCU_SGL_SIZE] __attribute__ ((aligned(32)));
|
||||
|
||||
/*
|
||||
|
@ -57,120 +57,30 @@
|
||||
#include "unsolicited_frame_control.h"
|
||||
#include "registers.h"
|
||||
|
||||
/**
|
||||
* This method will program the unsolicited frames (UFs) into the UF address
|
||||
* table and construct the UF frame structure being modeled in the core. It
|
||||
* will handle the case where some of the UFs are not being used and thus
|
||||
* should have entries programmed to zero in the address table.
|
||||
* @uf_control: This parameter specifies the unsolicted frame control object
|
||||
* for which to construct the unsolicited frames objects.
|
||||
* @uf_buffer_phys_address: This parameter specifies the physical address for
|
||||
* the first unsolicited frame buffer.
|
||||
* @uf_buffer_virt_address: This parameter specifies the virtual address for
|
||||
* the first unsolicited frame buffer.
|
||||
* @unused_uf_header_entries: This parameter specifies the number of unused UF
|
||||
* headers. This value can be non-zero when there are a non-power of 2
|
||||
* number of unsolicited frames being supported.
|
||||
* @used_uf_header_entries: This parameter specifies the number of actually
|
||||
* utilized UF headers.
|
||||
*
|
||||
*/
|
||||
static void scic_sds_unsolicited_frame_control_construct_frames(
|
||||
struct scic_sds_unsolicited_frame_control *uf_control,
|
||||
dma_addr_t uf_buffer_phys_address,
|
||||
void *uf_buffer_virt_address,
|
||||
u32 unused_uf_header_entries,
|
||||
u32 used_uf_header_entries)
|
||||
{
|
||||
u32 index;
|
||||
struct scic_sds_unsolicited_frame *uf;
|
||||
|
||||
/*
|
||||
* Program the unused buffers into the UF address table and the
|
||||
* controller's array of UFs.
|
||||
*/
|
||||
for (index = 0; index < unused_uf_header_entries; index++) {
|
||||
uf = &uf_control->buffers.array[index];
|
||||
|
||||
uf->buffer = NULL;
|
||||
uf_control->address_table.array[index] = 0;
|
||||
uf->header = &uf_control->headers.array[index];
|
||||
uf->state = UNSOLICITED_FRAME_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Program the actual used UF buffers into the UF address table and
|
||||
* the controller's array of UFs.
|
||||
*/
|
||||
for (index = unused_uf_header_entries;
|
||||
index < unused_uf_header_entries + used_uf_header_entries;
|
||||
index++) {
|
||||
uf = &uf_control->buffers.array[index];
|
||||
|
||||
uf_control->address_table.array[index] = uf_buffer_phys_address;
|
||||
|
||||
uf->buffer = uf_buffer_virt_address;
|
||||
uf->header = &uf_control->headers.array[index];
|
||||
uf->state = UNSOLICITED_FRAME_EMPTY;
|
||||
|
||||
/*
|
||||
* Increment the address of the physical and virtual memory
|
||||
* pointers. Everything is aligned on 1k boundary with an
|
||||
* increment of 1k.
|
||||
*/
|
||||
uf_buffer_virt_address += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
uf_buffer_phys_address += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
int scic_sds_unsolicited_frame_control_construct(struct scic_sds_controller *scic)
|
||||
{
|
||||
struct scic_sds_unsolicited_frame_control *uf_control = &scic->uf_control;
|
||||
u32 unused_uf_header_entries;
|
||||
u32 used_uf_header_entries;
|
||||
u32 used_uf_buffer_bytes;
|
||||
u32 unused_uf_header_bytes;
|
||||
u32 used_uf_header_bytes;
|
||||
dma_addr_t uf_buffer_phys_address;
|
||||
void *uf_buffer_virt_address;
|
||||
struct scic_sds_unsolicited_frame *uf;
|
||||
u32 buf_len, header_len, i;
|
||||
dma_addr_t dma;
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* The UF buffer address table size must be programmed to a power
|
||||
* of 2. Find the first power of 2 that is equal to or greater then
|
||||
* the number of unsolicited frame buffers to be utilized.
|
||||
*/
|
||||
uf_control->address_table.count = SCU_MIN_UF_TABLE_ENTRIES;
|
||||
while (uf_control->address_table.count < uf_control->buffers.count &&
|
||||
uf_control->address_table.count < SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES)
|
||||
uf_control->address_table.count <<= 1;
|
||||
void *virt;
|
||||
|
||||
/*
|
||||
* Prepare all of the memory sizes for the UF headers, UF address
|
||||
* table, and UF buffers themselves.
|
||||
*/
|
||||
used_uf_buffer_bytes = uf_control->buffers.count
|
||||
* SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
unused_uf_header_entries = uf_control->address_table.count
|
||||
- uf_control->buffers.count;
|
||||
used_uf_header_entries = uf_control->buffers.count;
|
||||
unused_uf_header_bytes = unused_uf_header_entries
|
||||
* sizeof(struct scu_unsolicited_frame_header);
|
||||
used_uf_header_bytes = used_uf_header_entries
|
||||
* sizeof(struct scu_unsolicited_frame_header);
|
||||
|
||||
size = used_uf_buffer_bytes + used_uf_header_bytes +
|
||||
uf_control->address_table.count * sizeof(dma_addr_t);
|
||||
|
||||
buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
|
||||
size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(dma_addr_t);
|
||||
|
||||
/*
|
||||
* The Unsolicited Frame buffers are set at the start of the UF
|
||||
* memory descriptor entry. The headers and address table will be
|
||||
* placed after the buffers.
|
||||
*/
|
||||
uf_buffer_virt_address = dmam_alloc_coherent(scic_to_dev(scic), size,
|
||||
&uf_buffer_phys_address, GFP_KERNEL);
|
||||
if (!uf_buffer_virt_address)
|
||||
virt = dmam_alloc_coherent(scic_to_dev(scic), size, &dma, GFP_KERNEL);
|
||||
if (!virt)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
@ -183,15 +93,8 @@ int scic_sds_unsolicited_frame_control_construct(struct scic_sds_controller *sci
|
||||
* headers, since we program the UF address table pointers to
|
||||
* NULL.
|
||||
*/
|
||||
uf_control->headers.physical_address =
|
||||
uf_buffer_phys_address +
|
||||
used_uf_buffer_bytes -
|
||||
unused_uf_header_bytes;
|
||||
|
||||
uf_control->headers.array =
|
||||
uf_buffer_virt_address +
|
||||
used_uf_buffer_bytes -
|
||||
unused_uf_header_bytes;
|
||||
uf_control->headers.physical_address = dma + buf_len;
|
||||
uf_control->headers.array = virt + buf_len;
|
||||
|
||||
/*
|
||||
* Program the location of the UF address table into the SCU.
|
||||
@ -200,16 +103,8 @@ int scic_sds_unsolicited_frame_control_construct(struct scic_sds_controller *sci
|
||||
* byte boundary already due to above programming headers being on a
|
||||
* 64-bit boundary and headers are on a 64-bytes in size.
|
||||
*/
|
||||
uf_control->address_table.physical_address =
|
||||
uf_buffer_phys_address +
|
||||
used_uf_buffer_bytes +
|
||||
used_uf_header_bytes;
|
||||
|
||||
uf_control->address_table.array =
|
||||
uf_buffer_virt_address +
|
||||
used_uf_buffer_bytes +
|
||||
used_uf_header_bytes;
|
||||
|
||||
uf_control->address_table.physical_address = dma + buf_len + header_len;
|
||||
uf_control->address_table.array = virt + buf_len + header_len;
|
||||
uf_control->get = 0;
|
||||
|
||||
/*
|
||||
@ -220,16 +115,26 @@ int scic_sds_unsolicited_frame_control_construct(struct scic_sds_controller *sci
|
||||
* - Aligned on a 1KB boundary. */
|
||||
|
||||
/*
|
||||
* If the user provided less then the maximum amount of memory,
|
||||
* then be sure that we programm the first entries in the UF
|
||||
* address table to NULL. */
|
||||
scic_sds_unsolicited_frame_control_construct_frames(
|
||||
uf_control,
|
||||
uf_buffer_phys_address,
|
||||
uf_buffer_virt_address,
|
||||
unused_uf_header_entries,
|
||||
used_uf_header_entries
|
||||
);
|
||||
* Program the actual used UF buffers into the UF address table and
|
||||
* the controller's array of UFs.
|
||||
*/
|
||||
for (i = 0; i < SCU_MAX_UNSOLICITED_FRAMES; i++) {
|
||||
uf = &uf_control->buffers.array[i];
|
||||
|
||||
uf_control->address_table.array[i] = dma;
|
||||
|
||||
uf->buffer = virt;
|
||||
uf->header = &uf_control->headers.array[i];
|
||||
uf->state = UNSOLICITED_FRAME_EMPTY;
|
||||
|
||||
/*
|
||||
* Increment the address of the physical and virtual memory
|
||||
* pointers. Everything is aligned on 1k boundary with an
|
||||
* increment of 1k.
|
||||
*/
|
||||
virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -247,7 +152,7 @@ enum sci_status scic_sds_unsolicited_frame_control_get_header(
|
||||
u32 frame_index,
|
||||
void **frame_header)
|
||||
{
|
||||
if (frame_index < uf_control->address_table.count) {
|
||||
if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) {
|
||||
/*
|
||||
* Skip the first word in the frame since this is a controll word used
|
||||
* by the hardware. */
|
||||
@ -272,7 +177,7 @@ enum sci_status scic_sds_unsolicited_frame_control_get_buffer(
|
||||
u32 frame_index,
|
||||
void **frame_buffer)
|
||||
{
|
||||
if (frame_index < uf_control->address_table.count) {
|
||||
if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) {
|
||||
*frame_buffer = uf_control->buffers.array[frame_index].buffer;
|
||||
|
||||
return SCI_SUCCESS;
|
||||
@ -298,26 +203,24 @@ bool scic_sds_unsolicited_frame_control_release_frame(
|
||||
u32 frame_get;
|
||||
u32 frame_cycle;
|
||||
|
||||
frame_get = uf_control->get & (uf_control->address_table.count - 1);
|
||||
frame_cycle = uf_control->get & uf_control->address_table.count;
|
||||
frame_get = uf_control->get & (SCU_MAX_UNSOLICITED_FRAMES - 1);
|
||||
frame_cycle = uf_control->get & SCU_MAX_UNSOLICITED_FRAMES;
|
||||
|
||||
/*
|
||||
* In the event there are NULL entries in the UF table, we need to
|
||||
* advance the get pointer in order to find out if this frame should
|
||||
* be released (i.e. update the get pointer). */
|
||||
while (((lower_32_bits(uf_control->address_table.array[frame_get])
|
||||
== 0) &&
|
||||
(upper_32_bits(uf_control->address_table.array[frame_get])
|
||||
== 0)) &&
|
||||
(frame_get < uf_control->address_table.count))
|
||||
while (lower_32_bits(uf_control->address_table.array[frame_get]) == 0 &&
|
||||
upper_32_bits(uf_control->address_table.array[frame_get]) == 0 &&
|
||||
frame_get < SCU_MAX_UNSOLICITED_FRAMES)
|
||||
frame_get++;
|
||||
|
||||
/*
|
||||
* The table has a NULL entry as it's last element. This is
|
||||
* illegal. */
|
||||
BUG_ON(frame_get >= uf_control->address_table.count);
|
||||
BUG_ON(frame_get >= SCU_MAX_UNSOLICITED_FRAMES);
|
||||
|
||||
if (frame_index < uf_control->address_table.count) {
|
||||
if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) {
|
||||
uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED;
|
||||
|
||||
/*
|
||||
@ -333,9 +236,8 @@ bool scic_sds_unsolicited_frame_control_release_frame(
|
||||
INCREMENT_QUEUE_GET(
|
||||
frame_get,
|
||||
frame_cycle,
|
||||
uf_control->address_table.count - 1,
|
||||
uf_control->address_table.count
|
||||
);
|
||||
SCU_MAX_UNSOLICITED_FRAMES - 1,
|
||||
SCU_MAX_UNSOLICITED_FRAMES);
|
||||
}
|
||||
|
||||
uf_control->get =
|
||||
|
@ -144,25 +144,18 @@ struct scic_sds_uf_header_array {
|
||||
*/
|
||||
struct scic_sds_uf_buffer_array {
|
||||
/**
|
||||
* This field is the minimum number of unsolicited frames supported by the
|
||||
* hardware and the number of unsolicited frames requested by the software.
|
||||
*/
|
||||
u32 count;
|
||||
|
||||
/**
|
||||
* This field is the SCIC_UNSOLICITED_FRAME data its used to manage
|
||||
* This field is the unsolicited frame data its used to manage
|
||||
* the data for the unsolicited frame requests. It also represents
|
||||
* the virtual address location that corresponds to the
|
||||
* physical_address field.
|
||||
*/
|
||||
struct scic_sds_unsolicited_frame array[SCU_UNSOLICITED_FRAME_CONTROL_ARRAY_SIZE];
|
||||
struct scic_sds_unsolicited_frame array[SCU_MAX_UNSOLICITED_FRAMES];
|
||||
|
||||
/**
|
||||
* This field specifies the physical address location for the UF
|
||||
* buffer array.
|
||||
*/
|
||||
dma_addr_t physical_address;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -173,15 +166,6 @@ struct scic_sds_uf_buffer_array {
|
||||
* 1KB buffers into which the silicon will DMA unsolicited frames.
|
||||
*/
|
||||
struct scic_sds_uf_address_table_array {
|
||||
/**
|
||||
* This field specifies the actual programmed size of the
|
||||
* unsolicited frame buffer address table. The size of the table
|
||||
* can be larger than the actual number of UF buffers, but it must
|
||||
* be a power of 2 and the last entry in the table is not allowed
|
||||
* to be NULL.
|
||||
*/
|
||||
u32 count;
|
||||
|
||||
/**
|
||||
* This field represents a virtual pointer that refers to the
|
||||
* starting address of the UF address table.
|
||||
|
Loading…
Reference in New Issue
Block a user