Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2013 - 2019 Intel Corporation. */
0003 
0004 #include "fm10k_vf.h"
0005 
0006 /**
0007  *  fm10k_stop_hw_vf - Stop Tx/Rx units
0008  *  @hw: pointer to hardware structure
0009  *
0010  **/
0011 static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
0012 {
0013     u8 *perm_addr = hw->mac.perm_addr;
0014     u32 bal = 0, bah = 0, tdlen;
0015     s32 err;
0016     u16 i;
0017 
0018     /* we need to disable the queues before taking further steps */
0019     err = fm10k_stop_hw_generic(hw);
0020     if (err && err != FM10K_ERR_REQUESTS_PENDING)
0021         return err;
0022 
0023     /* If permanent address is set then we need to restore it */
0024     if (is_valid_ether_addr(perm_addr)) {
0025         bal = (((u32)perm_addr[3]) << 24) |
0026               (((u32)perm_addr[4]) << 16) |
0027               (((u32)perm_addr[5]) << 8);
0028         bah = (((u32)0xFF)     << 24) |
0029               (((u32)perm_addr[0]) << 16) |
0030               (((u32)perm_addr[1]) << 8) |
0031                ((u32)perm_addr[2]);
0032     }
0033 
0034     /* restore default itr_scale for next VF initialization */
0035     tdlen = hw->mac.itr_scale << FM10K_TDLEN_ITR_SCALE_SHIFT;
0036 
0037     /* The queues have already been disabled so we just need to
0038      * update their base address registers
0039      */
0040     for (i = 0; i < hw->mac.max_queues; i++) {
0041         fm10k_write_reg(hw, FM10K_TDBAL(i), bal);
0042         fm10k_write_reg(hw, FM10K_TDBAH(i), bah);
0043         fm10k_write_reg(hw, FM10K_RDBAL(i), bal);
0044         fm10k_write_reg(hw, FM10K_RDBAH(i), bah);
0045         /* Restore ITR scale in software-defined mechanism in TDLEN
0046          * for next VF initialization. See definition of
0047          * FM10K_TDLEN_ITR_SCALE_SHIFT for more details on the use of
0048          * TDLEN here.
0049          */
0050         fm10k_write_reg(hw, FM10K_TDLEN(i), tdlen);
0051     }
0052 
0053     return err;
0054 }
0055 
0056 /**
0057  *  fm10k_reset_hw_vf - VF hardware reset
0058  *  @hw: pointer to hardware structure
0059  *
0060  *  This function should return the hardware to a state similar to the
0061  *  one it is in after just being initialized.
0062  **/
0063 static s32 fm10k_reset_hw_vf(struct fm10k_hw *hw)
0064 {
0065     s32 err;
0066 
0067     /* shut down queues we own and reset DMA configuration */
0068     err = fm10k_stop_hw_vf(hw);
0069     if (err == FM10K_ERR_REQUESTS_PENDING)
0070         hw->mac.reset_while_pending++;
0071     else if (err)
0072         return err;
0073 
0074     /* Inititate VF reset */
0075     fm10k_write_reg(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST);
0076 
0077     /* Flush write and allow 100us for reset to complete */
0078     fm10k_write_flush(hw);
0079     udelay(FM10K_RESET_TIMEOUT);
0080 
0081     /* Clear reset bit and verify it was cleared */
0082     fm10k_write_reg(hw, FM10K_VFCTRL, 0);
0083     if (fm10k_read_reg(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST)
0084         return FM10K_ERR_RESET_FAILED;
0085 
0086     return 0;
0087 }
0088 
0089 /**
0090  *  fm10k_init_hw_vf - VF hardware initialization
0091  *  @hw: pointer to hardware structure
0092  *
0093  **/
0094 static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
0095 {
0096     u32 tqdloc, tqdloc0 = ~fm10k_read_reg(hw, FM10K_TQDLOC(0));
0097     s32 err;
0098     u16 i;
0099 
0100     /* verify we have at least 1 queue */
0101     if (!~fm10k_read_reg(hw, FM10K_TXQCTL(0)) ||
0102         !~fm10k_read_reg(hw, FM10K_RXQCTL(0))) {
0103         err = FM10K_ERR_NO_RESOURCES;
0104         goto reset_max_queues;
0105     }
0106 
0107     /* determine how many queues we have */
0108     for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) {
0109         /* verify the Descriptor cache offsets are increasing */
0110         tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i));
0111         if (!tqdloc || (tqdloc == tqdloc0))
0112             break;
0113 
0114         /* check to verify the PF doesn't own any of our queues */
0115         if (!~fm10k_read_reg(hw, FM10K_TXQCTL(i)) ||
0116             !~fm10k_read_reg(hw, FM10K_RXQCTL(i)))
0117             break;
0118     }
0119 
0120     /* shut down queues we own and reset DMA configuration */
0121     err = fm10k_disable_queues_generic(hw, i);
0122     if (err)
0123         goto reset_max_queues;
0124 
0125     /* record maximum queue count */
0126     hw->mac.max_queues = i;
0127 
0128     /* fetch default VLAN and ITR scale */
0129     hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) &
0130                    FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
0131     /* Read the ITR scale from TDLEN. See the definition of
0132      * FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
0133      * used here.
0134      */
0135     hw->mac.itr_scale = (fm10k_read_reg(hw, FM10K_TDLEN(0)) &
0136                  FM10K_TDLEN_ITR_SCALE_MASK) >>
0137                 FM10K_TDLEN_ITR_SCALE_SHIFT;
0138 
0139     return 0;
0140 
0141 reset_max_queues:
0142     hw->mac.max_queues = 0;
0143 
0144     return err;
0145 }
0146 
0147 /* This structure defines the attibutes to be parsed below */
0148 const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = {
0149     FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN),
0150     FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET),
0151     FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC),
0152     FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC),
0153     FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST),
0154     FM10K_TLV_ATTR_LAST
0155 };
0156 
0157 /**
0158  *  fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table
0159  *  @hw: pointer to hardware structure
0160  *  @vid: VLAN ID to add to table
0161  *  @vsi: Reserved, should always be 0
0162  *  @set: Indicates if this is a set or clear operation
0163  *
0164  *  This function adds or removes the corresponding VLAN ID from the VLAN
0165  *  filter table for this VF.
0166  **/
0167 static s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set)
0168 {
0169     struct fm10k_mbx_info *mbx = &hw->mbx;
0170     u32 msg[4];
0171 
0172     /* verify the index is not set */
0173     if (vsi)
0174         return FM10K_ERR_PARAM;
0175 
0176     /* clever trick to verify reserved bits in both vid and length */
0177     if ((vid << 16 | vid) >> 28)
0178         return FM10K_ERR_PARAM;
0179 
0180     /* encode set bit into the VLAN ID */
0181     if (!set)
0182         vid |= FM10K_VLAN_CLEAR;
0183 
0184     /* generate VLAN request */
0185     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
0186     fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid);
0187 
0188     /* load onto outgoing mailbox */
0189     return mbx->ops.enqueue_tx(hw, mbx, msg);
0190 }
0191 
0192 /**
0193  *  fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message
0194  *  @hw: pointer to the HW structure
0195  *  @results: Attributes for message
0196  *  @mbx: unused mailbox data
0197  *
0198  *  This function should determine the MAC address for the VF
0199  **/
0200 s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results,
0201               struct fm10k_mbx_info __always_unused *mbx)
0202 {
0203     u8 perm_addr[ETH_ALEN];
0204     u16 vid;
0205     s32 err;
0206 
0207     /* record MAC address requested */
0208     err = fm10k_tlv_attr_get_mac_vlan(
0209                     results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC],
0210                     perm_addr, &vid);
0211     if (err)
0212         return err;
0213 
0214     ether_addr_copy(hw->mac.perm_addr, perm_addr);
0215     hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1);
0216     hw->mac.vlan_override = !!(vid & FM10K_VLAN_OVERRIDE);
0217 
0218     return 0;
0219 }
0220 
0221 /**
0222  *  fm10k_read_mac_addr_vf - Read device MAC address
0223  *  @hw: pointer to the HW structure
0224  *
0225  *  This function should determine the MAC address for the VF
0226  **/
0227 static s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw)
0228 {
0229     u8 perm_addr[ETH_ALEN];
0230     u32 base_addr;
0231 
0232     base_addr = fm10k_read_reg(hw, FM10K_TDBAL(0));
0233 
0234     /* last byte should be 0 */
0235     if (base_addr << 24)
0236         return  FM10K_ERR_INVALID_MAC_ADDR;
0237 
0238     perm_addr[3] = (u8)(base_addr >> 24);
0239     perm_addr[4] = (u8)(base_addr >> 16);
0240     perm_addr[5] = (u8)(base_addr >> 8);
0241 
0242     base_addr = fm10k_read_reg(hw, FM10K_TDBAH(0));
0243 
0244     /* first byte should be all 1's */
0245     if ((~base_addr) >> 24)
0246         return  FM10K_ERR_INVALID_MAC_ADDR;
0247 
0248     perm_addr[0] = (u8)(base_addr >> 16);
0249     perm_addr[1] = (u8)(base_addr >> 8);
0250     perm_addr[2] = (u8)(base_addr);
0251 
0252     ether_addr_copy(hw->mac.perm_addr, perm_addr);
0253     ether_addr_copy(hw->mac.addr, perm_addr);
0254 
0255     return 0;
0256 }
0257 
0258 /**
0259  *  fm10k_update_uc_addr_vf - Update device unicast addresses
0260  *  @hw: pointer to the HW structure
0261  *  @glort: unused
0262  *  @mac: MAC address to add/remove from table
0263  *  @vid: VLAN ID to add/remove from table
0264  *  @add: Indicates if this is an add or remove operation
0265  *  @flags: flags field to indicate add and secure - unused
0266  *
0267  *  This function is used to add or remove unicast MAC addresses for
0268  *  the VF.
0269  **/
0270 static s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw,
0271                    u16 __always_unused glort,
0272                    const u8 *mac, u16 vid, bool add,
0273                    u8 __always_unused flags)
0274 {
0275     struct fm10k_mbx_info *mbx = &hw->mbx;
0276     u32 msg[7];
0277 
0278     /* verify VLAN ID is valid */
0279     if (vid >= FM10K_VLAN_TABLE_VID_MAX)
0280         return FM10K_ERR_PARAM;
0281 
0282     /* verify MAC address is valid */
0283     if (!is_valid_ether_addr(mac))
0284         return FM10K_ERR_PARAM;
0285 
0286     /* verify we are not locked down on the MAC address */
0287     if (is_valid_ether_addr(hw->mac.perm_addr) &&
0288         !ether_addr_equal(hw->mac.perm_addr, mac))
0289         return FM10K_ERR_PARAM;
0290 
0291     /* add bit to notify us if this is a set or clear operation */
0292     if (!add)
0293         vid |= FM10K_VLAN_CLEAR;
0294 
0295     /* generate VLAN request */
0296     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
0297     fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid);
0298 
0299     /* load onto outgoing mailbox */
0300     return mbx->ops.enqueue_tx(hw, mbx, msg);
0301 }
0302 
0303 /**
0304  *  fm10k_update_mc_addr_vf - Update device multicast addresses
0305  *  @hw: pointer to the HW structure
0306  *  @glort: unused
0307  *  @mac: MAC address to add/remove from table
0308  *  @vid: VLAN ID to add/remove from table
0309  *  @add: Indicates if this is an add or remove operation
0310  *
0311  *  This function is used to add or remove multicast MAC addresses for
0312  *  the VF.
0313  **/
0314 static s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw,
0315                    u16 __always_unused glort,
0316                    const u8 *mac, u16 vid, bool add)
0317 {
0318     struct fm10k_mbx_info *mbx = &hw->mbx;
0319     u32 msg[7];
0320 
0321     /* verify VLAN ID is valid */
0322     if (vid >= FM10K_VLAN_TABLE_VID_MAX)
0323         return FM10K_ERR_PARAM;
0324 
0325     /* verify multicast address is valid */
0326     if (!is_multicast_ether_addr(mac))
0327         return FM10K_ERR_PARAM;
0328 
0329     /* add bit to notify us if this is a set or clear operation */
0330     if (!add)
0331         vid |= FM10K_VLAN_CLEAR;
0332 
0333     /* generate VLAN request */
0334     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
0335     fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST,
0336                     mac, vid);
0337 
0338     /* load onto outgoing mailbox */
0339     return mbx->ops.enqueue_tx(hw, mbx, msg);
0340 }
0341 
0342 /**
0343  *  fm10k_update_int_moderator_vf - Request update of interrupt moderator list
0344  *  @hw: pointer to hardware structure
0345  *
0346  *  This function will issue a request to the PF to rescan our MSI-X table
0347  *  and to update the interrupt moderator linked list.
0348  **/
0349 static void fm10k_update_int_moderator_vf(struct fm10k_hw *hw)
0350 {
0351     struct fm10k_mbx_info *mbx = &hw->mbx;
0352     u32 msg[1];
0353 
0354     /* generate MSI-X request */
0355     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX);
0356 
0357     /* load onto outgoing mailbox */
0358     mbx->ops.enqueue_tx(hw, mbx, msg);
0359 }
0360 
0361 /* This structure defines the attibutes to be parsed below */
0362 const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = {
0363     FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE),
0364     FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE),
0365     FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY),
0366     FM10K_TLV_ATTR_LAST
0367 };
0368 
0369 /**
0370  *  fm10k_msg_lport_state_vf - Message handler for lport_state message from PF
0371  *  @hw: Pointer to hardware structure
0372  *  @results: pointer array containing parsed data
0373  *  @mbx: Pointer to mailbox information structure
0374  *
0375  *  This handler is meant to capture the indication from the PF that we
0376  *  are ready to bring up the interface.
0377  **/
0378 s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results,
0379                  struct fm10k_mbx_info __always_unused *mbx)
0380 {
0381     hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ?
0382                  FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO;
0383 
0384     return 0;
0385 }
0386 
0387 /**
0388  *  fm10k_update_lport_state_vf - Update device state in lower device
0389  *  @hw: pointer to the HW structure
0390  *  @glort: unused
0391  *  @count: number of logical ports to enable - unused (always 1)
0392  *  @enable: boolean value indicating if this is an enable or disable request
0393  *
0394  *  Notify the lower device of a state change.  If the lower device is
0395  *  enabled we can add filters, if it is disabled all filters for this
0396  *  logical port are flushed.
0397  **/
0398 static s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw,
0399                        u16 __always_unused glort,
0400                        u16 __always_unused count, bool enable)
0401 {
0402     struct fm10k_mbx_info *mbx = &hw->mbx;
0403     u32 msg[2];
0404 
0405     /* reset glort mask 0 as we have to wait to be enabled */
0406     hw->mac.dglort_map = FM10K_DGLORTMAP_NONE;
0407 
0408     /* generate port state request */
0409     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
0410     if (!enable)
0411         fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE);
0412 
0413     /* load onto outgoing mailbox */
0414     return mbx->ops.enqueue_tx(hw, mbx, msg);
0415 }
0416 
0417 /**
0418  *  fm10k_update_xcast_mode_vf - Request update of multicast mode
0419  *  @hw: pointer to hardware structure
0420  *  @glort: unused
0421  *  @mode: integer value indicating mode being requested
0422  *
0423  *  This function will attempt to request a higher mode for the port
0424  *  so that it can enable either multicast, multicast promiscuous, or
0425  *  promiscuous mode of operation.
0426  **/
0427 static s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw,
0428                       u16 __always_unused glort, u8 mode)
0429 {
0430     struct fm10k_mbx_info *mbx = &hw->mbx;
0431     u32 msg[3];
0432 
0433     if (mode > FM10K_XCAST_MODE_NONE)
0434         return FM10K_ERR_PARAM;
0435 
0436     /* generate message requesting to change xcast mode */
0437     fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
0438     fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode);
0439 
0440     /* load onto outgoing mailbox */
0441     return mbx->ops.enqueue_tx(hw, mbx, msg);
0442 }
0443 
0444 /**
0445  *  fm10k_update_hw_stats_vf - Updates hardware related statistics of VF
0446  *  @hw: pointer to hardware structure
0447  *  @stats: pointer to statistics structure
0448  *
0449  *  This function collects and aggregates per queue hardware statistics.
0450  **/
0451 static void fm10k_update_hw_stats_vf(struct fm10k_hw *hw,
0452                      struct fm10k_hw_stats *stats)
0453 {
0454     fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues);
0455 }
0456 
0457 /**
0458  *  fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF
0459  *  @hw: pointer to hardware structure
0460  *  @stats: pointer to the stats structure to update
0461  *
0462  *  This function resets the base for queue hardware statistics.
0463  **/
0464 static void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw,
0465                      struct fm10k_hw_stats *stats)
0466 {
0467     /* Unbind Queue Statistics */
0468     fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues);
0469 
0470     /* Reinitialize bases for all stats */
0471     fm10k_update_hw_stats_vf(hw, stats);
0472 }
0473 
0474 /**
0475  *  fm10k_configure_dglort_map_vf - Configures GLORT entry and queues
0476  *  @hw: pointer to hardware structure
0477  *  @dglort: pointer to dglort configuration structure
0478  *
0479  *  Reads the configuration structure contained in dglort_cfg and uses
0480  *  that information to then populate a DGLORTMAP/DEC entry and the queues
0481  *  to which it has been assigned.
0482  **/
0483 static s32 fm10k_configure_dglort_map_vf(struct fm10k_hw __always_unused *hw,
0484                      struct fm10k_dglort_cfg *dglort)
0485 {
0486     /* verify the dglort pointer */
0487     if (!dglort)
0488         return FM10K_ERR_PARAM;
0489 
0490     /* stub for now until we determine correct message for this */
0491 
0492     return 0;
0493 }
0494 
0495 static const struct fm10k_msg_data fm10k_msg_data_vf[] = {
0496     FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
0497     FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf),
0498     FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf),
0499     FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
0500 };
0501 
0502 static const struct fm10k_mac_ops mac_ops_vf = {
0503     .get_bus_info       = fm10k_get_bus_info_generic,
0504     .reset_hw       = fm10k_reset_hw_vf,
0505     .init_hw        = fm10k_init_hw_vf,
0506     .start_hw       = fm10k_start_hw_generic,
0507     .stop_hw        = fm10k_stop_hw_vf,
0508     .update_vlan        = fm10k_update_vlan_vf,
0509     .read_mac_addr      = fm10k_read_mac_addr_vf,
0510     .update_uc_addr     = fm10k_update_uc_addr_vf,
0511     .update_mc_addr     = fm10k_update_mc_addr_vf,
0512     .update_xcast_mode  = fm10k_update_xcast_mode_vf,
0513     .update_int_moderator   = fm10k_update_int_moderator_vf,
0514     .update_lport_state = fm10k_update_lport_state_vf,
0515     .update_hw_stats    = fm10k_update_hw_stats_vf,
0516     .rebind_hw_stats    = fm10k_rebind_hw_stats_vf,
0517     .configure_dglort_map   = fm10k_configure_dglort_map_vf,
0518     .get_host_state     = fm10k_get_host_state_generic,
0519 };
0520 
0521 static s32 fm10k_get_invariants_vf(struct fm10k_hw *hw)
0522 {
0523     fm10k_get_invariants_generic(hw);
0524 
0525     return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0);
0526 }
0527 
0528 const struct fm10k_info fm10k_vf_info = {
0529     .mac        = fm10k_mac_vf,
0530     .get_invariants = fm10k_get_invariants_vf,
0531     .mac_ops    = &mac_ops_vf,
0532 };