Skip to content

Commit

Permalink
ionic: Add port management commands
Browse files Browse the repository at this point in the history
The port management commands apply to the physical port
associated with the PCI device, which might be shared among
several logical interfaces.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Shannon Nelson authored and David S. Miller committed Sep 5, 2019
1 parent fbfb803 commit 0443659
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ int ionic_identify(struct ionic *ionic);
int ionic_init(struct ionic *ionic);
int ionic_reset(struct ionic *ionic);

int ionic_port_identify(struct ionic *ionic);
int ionic_port_init(struct ionic *ionic);
int ionic_port_reset(struct ionic *ionic);

#endif /* _IONIC_H_ */
16 changes: 16 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,27 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_teardown;
}

/* Configure the ports */
err = ionic_port_identify(ionic);
if (err) {
dev_err(dev, "Cannot identify port: %d, aborting\n", err);
goto err_out_reset;
}

err = ionic_port_init(ionic);
if (err) {
dev_err(dev, "Cannot init port: %d, aborting\n", err);
goto err_out_reset;
}

err = ionic_devlink_register(ionic);
if (err)
dev_err(dev, "Cannot register devlink: %d\n", err);

return 0;

err_out_reset:
ionic_reset(ionic);
err_out_teardown:
ionic_dev_teardown(ionic);
err_out_unmap_bars:
Expand All @@ -170,6 +185,7 @@ static void ionic_remove(struct pci_dev *pdev)
return;

ionic_devlink_unregister(ionic);
ionic_port_reset(ionic);
ionic_reset(ionic);
ionic_dev_teardown(ionic);
ionic_unmap_bars(ionic);
Expand Down
92 changes: 92 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,95 @@ void ionic_dev_cmd_reset(struct ionic_dev *idev)

ionic_dev_cmd_go(idev, &cmd);
}

/* Port commands */
void ionic_dev_cmd_port_identify(struct ionic_dev *idev)
{
union ionic_dev_cmd cmd = {
.port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
.port_init.index = 0,
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_init(struct ionic_dev *idev)
{
union ionic_dev_cmd cmd = {
.port_init.opcode = IONIC_CMD_PORT_INIT,
.port_init.index = 0,
.port_init.info_pa = cpu_to_le64(idev->port_info_pa),
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_reset(struct ionic_dev *idev)
{
union ionic_dev_cmd cmd = {
.port_reset.opcode = IONIC_CMD_PORT_RESET,
.port_reset.index = 0,
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state)
{
union ionic_dev_cmd cmd = {
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
.port_setattr.index = 0,
.port_setattr.attr = IONIC_PORT_ATTR_STATE,
.port_setattr.state = state,
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed)
{
union ionic_dev_cmd cmd = {
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
.port_setattr.index = 0,
.port_setattr.attr = IONIC_PORT_ATTR_SPEED,
.port_setattr.speed = cpu_to_le32(speed),
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable)
{
union ionic_dev_cmd cmd = {
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
.port_setattr.index = 0,
.port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
.port_setattr.an_enable = an_enable,
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type)
{
union ionic_dev_cmd cmd = {
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
.port_setattr.index = 0,
.port_setattr.attr = IONIC_PORT_ATTR_FEC,
.port_setattr.fec_type = fec_type,
};

ionic_dev_cmd_go(idev, &cmd);
}

void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)
{
union ionic_dev_cmd cmd = {
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
.port_setattr.index = 0,
.port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
.port_setattr.pause_type = pause_type,
};

ionic_dev_cmd_go(idev, &cmd);
}
13 changes: 13 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ struct ionic_dev {
struct ionic_intr __iomem *intr_ctrl;
u64 __iomem *intr_status;

u32 port_info_sz;
struct ionic_port_info *port_info;
dma_addr_t port_info_pa;

struct ionic_devinfo dev_info;
};

Expand All @@ -135,4 +139,13 @@ void ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver);
void ionic_dev_cmd_init(struct ionic_dev *idev);
void ionic_dev_cmd_reset(struct ionic_dev *idev);

void ionic_dev_cmd_port_identify(struct ionic_dev *idev);
void ionic_dev_cmd_port_init(struct ionic_dev *idev);
void ionic_dev_cmd_port_reset(struct ionic_dev *idev);
void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state);
void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed);
void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable);
void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);

#endif /* _IONIC_DEV_H_ */
88 changes: 88 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,94 @@ int ionic_reset(struct ionic *ionic)
return err;
}

int ionic_port_identify(struct ionic *ionic)
{
struct ionic_identity *ident = &ionic->ident;
struct ionic_dev *idev = &ionic->idev;
size_t sz;
int err;

mutex_lock(&ionic->dev_cmd_lock);

ionic_dev_cmd_port_identify(idev);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
if (!err) {
sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data));
memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz);
}

mutex_unlock(&ionic->dev_cmd_lock);

return err;
}

int ionic_port_init(struct ionic *ionic)
{
struct ionic_identity *ident = &ionic->ident;
struct ionic_dev *idev = &ionic->idev;
size_t sz;
int err;

if (idev->port_info)
return 0;

idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
idev->port_info = dma_alloc_coherent(ionic->dev, idev->port_info_sz,
&idev->port_info_pa,
GFP_KERNEL);
if (!idev->port_info) {
dev_err(ionic->dev, "Failed to allocate port info, aborting\n");
return -ENOMEM;
}

sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));

mutex_lock(&ionic->dev_cmd_lock);

memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz);
ionic_dev_cmd_port_init(idev);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);

ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
(void)ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);

mutex_unlock(&ionic->dev_cmd_lock);
if (err) {
dev_err(ionic->dev, "Failed to init port\n");
dma_free_coherent(ionic->dev, idev->port_info_sz,
idev->port_info, idev->port_info_pa);
idev->port_info = NULL;
idev->port_info_pa = 0;
}

return err;
}

int ionic_port_reset(struct ionic *ionic)
{
struct ionic_dev *idev = &ionic->idev;
int err;

if (!idev->port_info)
return 0;

mutex_lock(&ionic->dev_cmd_lock);
ionic_dev_cmd_port_reset(idev);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
mutex_unlock(&ionic->dev_cmd_lock);

dma_free_coherent(ionic->dev, idev->port_info_sz,
idev->port_info, idev->port_info_pa);

idev->port_info = NULL;
idev->port_info_pa = 0;

if (err)
dev_err(ionic->dev, "Failed to reset port\n");

return err;
}

static int __init ionic_init_module(void)
{
pr_info("%s %s, ver %s\n",
Expand Down

0 comments on commit 0443659

Please sign in to comment.