Skip to content

Commit

Permalink
Merge branch 'master' into backport_ubuntu_16.04.2_4.4.0-62-generic
Browse files Browse the repository at this point in the history
  • Loading branch information
kelvin-cao committed Dec 27, 2019
2 parents c95b9a8 + 9ee89b0 commit 3d895e4
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 27 deletions.
46 changes: 26 additions & 20 deletions linux/switchtec.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define SWITCHTEC_EVENT_EN_CLI BIT(2)
#define SWITCHTEC_EVENT_EN_IRQ BIT(3)
#define SWITCHTEC_EVENT_FATAL BIT(4)
#define SWITCHTEC_EVENT_NOT_SUPP BIT(31)

#define SWITCHTEC_DMA_MRPC_EN BIT(0)

Expand Down Expand Up @@ -137,17 +138,21 @@ enum {
};

enum {
SWITCHTEC_GEN4_BL2_0_RUNNING = 0x01,
SWITCHTEC_GEN4_BL2_1_RUNNING = 0x02,
SWITCHTEC_GEN4_MAP0_RUNNING = 0x03,
SWITCHTEC_GEN4_MAP1_RUNNING = 0x04,
SWITCHTEC_GEN4_CFG0_RUNNING = 0x05,
SWITCHTEC_GEN4_CFG1_RUNNING = 0x06,
SWITCHTEC_GEN4_IMG0_RUNNING = 0x07,
SWITCHTEC_GEN4_IMG1_RUNNING = 0x08,
SWITCHTEC_GEN4_MAP0_RUNNING = 0x00,
SWITCHTEC_GEN4_MAP1_RUNNING = 0x01,
SWITCHTEC_GEN4_KEY0_RUNNING = 0x02,
SWITCHTEC_GEN4_KEY1_RUNNING = 0x03,
SWITCHTEC_GEN4_BL2_0_RUNNING = 0x04,
SWITCHTEC_GEN4_BL2_1_RUNNING = 0x05,
SWITCHTEC_GEN4_CFG0_RUNNING = 0x06,
SWITCHTEC_GEN4_CFG1_RUNNING = 0x07,
SWITCHTEC_GEN4_IMG0_RUNNING = 0x08,
SWITCHTEC_GEN4_IMG1_RUNNING = 0x09,
};

enum {
SWITCHTEC_GEN4_KEY0_ACTIVE = 0,
SWITCHTEC_GEN4_KEY1_ACTIVE = 1,
SWITCHTEC_GEN4_BL2_0_ACTIVE = 0,
SWITCHTEC_GEN4_BL2_1_ACTIVE = 1,
SWITCHTEC_GEN4_CFG0_ACTIVE = 0,
Expand Down Expand Up @@ -186,32 +191,32 @@ struct sys_info_regs_gen4 {
u8 mrpc_inband_ver;
u32 reserved3[7];
u32 fw_update_tmo;
u32 table_version_cfg;
u32 table_version_img;
u32 xml_version_cfg;
u32 xml_version_img;
u32 partition_id;
u16 bl2_running;
u16 cfg_running;
u16 img_running;
u16 reserved4;
u32 reserved5[43];
u16 key_running;
u32 reserved4[43];
u32 vendor_seeprom_twi;
u32 vendor_table_revision;
u32 vendor_specific_info[2];
u16 p2p_vendor_id;
u16 p2p_device_id;
u8 p2p_revision_id;
u8 reserved6[3];
u8 reserved5[3];
u32 p2p_class_id;
u16 subsystem_vendor_id;
u16 subsystem_id;
u32 p2p_serial_number[2];
u8 mac_addr[6];
u8 reserved7[2];
u32 reserved8[3];
u8 reserved6[2];
u32 reserved7[3];
char vendor_id[8];
char product_id[24];
char product_revision[2];
u16 reserved9;
u16 reserved8;
} __packed;

struct sys_info_regs {
Expand Down Expand Up @@ -260,16 +265,17 @@ struct flash_info_regs_gen4 {
unsigned char bl2;
unsigned char cfg;
unsigned char img;
unsigned char reserved;
unsigned char key;
} active_flag;

u32 reserved[3];

struct partition_info bl1;
struct partition_info bl2_0;
struct partition_info bl2_1;
struct partition_info map0;
struct partition_info map1;
struct partition_info key0;
struct partition_info key1;
struct partition_info bl2_0;
struct partition_info bl2_1;
struct partition_info cfg0;
struct partition_info cfg1;
struct partition_info img0;
Expand Down
6 changes: 5 additions & 1 deletion linux/switchtec_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@
#define SWITCHTEC_IOCTL_PART_VENDOR7 12
#define SWITCHTEC_IOCTL_PART_BL2_0 13
#define SWITCHTEC_IOCTL_PART_BL2_1 14
#define SWITCHTEC_IOCTL_PART_MAP_0 15
#define SWITCHTEC_IOCTL_PART_MAP_1 16
#define SWITCHTEC_IOCTL_PART_KEY_0 17
#define SWITCHTEC_IOCTL_PART_KEY_1 18

#define SWITCHTEC_NUM_PARTITIONS_GEN3 13
#define SWITCHTEC_NUM_PARTITIONS_GEN4 15
#define SWITCHTEC_NUM_PARTITIONS_GEN4 19

struct switchtec_ioctl_flash_info {
__u64 flash_length;
Expand Down
19 changes: 15 additions & 4 deletions ntb_hw_switchtec.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
if (rc)
return rc;

if (addr == 0 || size == 0) {
if (size == 0) {
if (idx < nr_direct_mw)
switchtec_ntb_mw_clr_direct(sndev, idx);
else
Expand Down Expand Up @@ -434,9 +434,19 @@ static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,
enum ntb_width *width)
{
struct switchtec_dev *stdev = sndev->stdev;
u32 pff;
u32 linksta;

pff = ioread32(&stdev->mmio_part_cfg_all[partition].vep_pff_inst_id);
if (pff == 0xFFFFFFFF) {
dev_warn(&sndev->stdev->dev,
"Invalid pff, setting speed/width to 0");
*speed = 0;
*width = 0;
return;
}

u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id);
u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);
linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);

if (speed)
*speed = (linksta >> 16) & 0xF;
Expand Down Expand Up @@ -853,6 +863,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low);

part_map = ioread64(&sndev->mmio_ntb->ep_map);
tpart_vec &= part_map;
part_map &= ~(1 << sndev->self_partition);

if (!tpart_vec) {
Expand All @@ -877,7 +888,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
}

sndev->peer_partition = __ffs64(tpart_vec);
if (!(part_map & (1 << sndev->peer_partition))) {
if (!(part_map & (1ULL << sndev->peer_partition))) {
dev_err(&sndev->stdev->dev,
"ntb target partition is not NT partition\n");
return -ENODEV;
Expand Down
137 changes: 136 additions & 1 deletion switchtec.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/aer.h>

#include "version.h"
MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
Expand Down Expand Up @@ -705,6 +706,26 @@ static int flash_part_info_gen4(struct switchtec_dev *stdev,
struct active_partition_info_gen4 __iomem *af = &fi->active_flag;

switch (info->flash_partition) {
case SWITCHTEC_IOCTL_PART_MAP_0:
set_fw_info_part(info, &fi->map0);
break;
case SWITCHTEC_IOCTL_PART_MAP_1:
set_fw_info_part(info, &fi->map1);
break;
case SWITCHTEC_IOCTL_PART_KEY_0:
set_fw_info_part(info, &fi->key0);
if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY0_ACTIVE)
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY0_RUNNING)
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_KEY_1:
set_fw_info_part(info, &fi->key1);
if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY1_ACTIVE)
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY1_RUNNING)
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_BL2_0:
set_fw_info_part(info, &fi->bl2_0);
if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_0_ACTIVE)
Expand Down Expand Up @@ -947,6 +968,9 @@ static int event_ctl(struct switchtec_dev *stdev,
return PTR_ERR(reg);

hdr = ioread32(reg);
if (hdr & SWITCHTEC_EVENT_NOT_SUPP)
return -ENOTSUPP;

for (i = 0; i < ARRAY_SIZE(ctl->data); i++)
ctl->data[i] = ioread32(&reg[i + 1]);

Expand Down Expand Up @@ -1019,7 +1043,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev,
for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) {
ctl.flags = event_flags;
ret = event_ctl(stdev, &ctl);
if (ret < 0)
if (ret < 0 && ret != -ENOTSUPP)
return ret;
}
} else {
Expand Down Expand Up @@ -1324,6 +1348,9 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
hdr_reg = event_regs[eid].map_reg(stdev, off, idx);
hdr = ioread32(hdr_reg);

if (hdr & SWITCHTEC_EVENT_NOT_SUPP)
return 0;

if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
return 0;

Expand Down Expand Up @@ -1662,6 +1689,8 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
goto err_devadd;

dev_info(&stdev->dev, "Management device registered.\n");
pci_enable_pcie_error_reporting(pdev);
pci_save_state(pdev);

return 0;

Expand All @@ -1688,6 +1717,111 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
put_device(&stdev->dev);
}

static void switchtec_pci_disable(struct pci_dev *pdev)
{
struct switchtec_dev *stdev = pci_get_drvdata(pdev);

if (pci_is_enabled(pdev)) {
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
}

stdev_kill(stdev);
}

static pci_ers_result_t switchtec_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
struct switchtec_dev *stdev = pci_get_drvdata(pdev);

/*
* A frozen channel requires a reset. When detected, this method
* will disable the device. The device will be restarted
* after the slot reset through driver's slot_reset callback.
*/
switch (state) {
case pci_channel_io_normal:
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
switchtec_pci_disable(pdev);
dev_info(&stdev->dev, "frozen state error detected - reset needed\n");
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
switchtec_pci_disable(pdev);
dev_info(&stdev->dev, "failure state error detected - request disconnect\n");
return PCI_ERS_RESULT_DISCONNECT;
}
return PCI_ERS_RESULT_NEED_RESET;
}

static pci_ers_result_t switchtec_pci_slot_reset(struct pci_dev *pdev)
{
struct switchtec_dev *stdev = pci_get_drvdata(pdev);
int rc;
unsigned long res_start, res_len;

dev_info(&stdev->dev, "slot_reset.\n");

pci_restore_state(pdev);

/*
* First, release PCI resources and memory regions
*/
if (stdev->dma_mrpc){
iowrite32(0, &stdev->mmio_mrpc->dma_en);
flush_wc_buf(stdev);
writeq(0, &stdev->mmio_mrpc->dma_addr);
dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
}

res_start = pci_resource_start(pdev, 0);
res_len = pci_resource_len(pdev, 0);

devm_release_mem_region(&pdev->dev, res_start, res_len);

/*
* Second, reinitialize PCI resources, remap memory regions and reenable events.
*/
rc = switchtec_init_pci(stdev, pdev);
if (rc) {
dev_err(&stdev->dev, "failed to reinitialize pci.\n");
goto err_ret;
}

iowrite32(SWITCHTEC_EVENT_CLEAR |
SWITCHTEC_EVENT_EN_IRQ,
&stdev->mmio_part_cfg->mrpc_comp_hdr);
enable_link_state_events(stdev);

if (stdev->dma_mrpc)
enable_dma_mrpc(stdev);

stdev->alive = true;
stdev->mrpc_busy = 0;

pci_enable_pcie_error_reporting(pdev);
pci_save_state(pdev);

return PCI_ERS_RESULT_RECOVERED;
err_ret:
return PCI_ERS_RESULT_DISCONNECT;
}

static void switchtec_pci_error_resume(struct pci_dev *pdev)
{
struct switchtec_dev *stdev = pci_get_drvdata(pdev);

dev_info(&stdev->dev, "resume.\n");
pci_cleanup_aer_uncorrect_error_status(pdev);
}

static const struct pci_error_handlers switchtec_pci_err_handler = {
.error_detected = switchtec_pci_error_detected,
.slot_reset = switchtec_pci_slot_reset,
.resume = switchtec_pci_error_resume,
};

#define SWITCHTEC_PCI_DEVICE(device_id, gen) \
{ \
.vendor = MICROSEMI_VENDOR_ID, \
Expand Down Expand Up @@ -1766,6 +1900,7 @@ static struct pci_driver switchtec_pci_driver = {
.id_table = switchtec_pci_tbl,
.probe = switchtec_pci_probe,
.remove = switchtec_pci_remove,
.err_handler = &switchtec_pci_err_handler,
};

static int __init switchtec_init(void)
Expand Down
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3
1.4

0 comments on commit 3d895e4

Please sign in to comment.